"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/preprocessors/snort_httpinspect.c" (16 Oct 2020, 170058 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "snort_httpinspect.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.9.16.1_vs_2.9.17.
1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2003-2013 Sourcefire, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation. You may not use, modify or
9 * distribute this program under any other version of the GNU General
10 * Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 ****************************************************************************/
22
23 /**
24 ** @file snort_httpinspect.c
25 **
26 ** @author Daniel Roelker <droelker@sourcefire.com>
27 **
28 ** @brief This file wraps the HttpInspect functionality for Snort
29 ** and starts the HttpInspect flow.
30 **
31 **
32 ** The file takes a Packet structure from the Snort IDS to start the
33 ** HttpInspect flow. This also uses the Stream Interface Module which
34 ** is also Snort-centric. Mainly, just a wrapper to HttpInspect
35 ** functionality, but a key part to starting the basic flow.
36 **
37 ** The main bulk of this file is taken up with user configuration and
38 ** parsing. The reason this is so large is because HttpInspect takes
39 ** very detailed configuration parameters for each specified server.
40 ** Hopefully every web server that is out there can be emulated
41 ** with these configuration options.
42 **
43 ** The main functions of note are:
44 ** - HttpInspectSnortConf::this is the configuration portion
45 ** - SnortHttpInspect::this is the actual inspection flow
46 ** - LogEvents:this is where we log the HttpInspect events
47 **
48 ** NOTES:
49 **
50 ** - 2.11.03: Initial Development. DJR
51 ** - 2.4.05: Added tab_uri_delimiter config option. AJM.
52 */
53 #include <assert.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <sys/types.h>
57 #include <limits.h>
58 #ifndef WIN32
59 #include <sys/socket.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #endif
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif
67
68 #include "snort.h"
69 #include "detect.h"
70 #include "decode.h"
71 #include "log.h"
72 #include "event.h"
73 #include "generators.h"
74 #include "snort_debug.h"
75 #include "plugbase.h"
76 #include "util.h"
77 #include "event_queue.h"
78 #include "session_common.h"
79 #include "session_api.h"
80 #include "stream_api.h"
81 #include "sfsnprintfappend.h"
82
83 #include "hi_return_codes.h"
84 #include "hi_ui_config.h"
85 #include "hi_ui_iis_unicode_map.h"
86 #include "hi_si.h"
87 #include "hi_mi.h"
88 #include "hi_norm.h"
89 #include "hi_client.h"
90 #include "snort_httpinspect.h"
91 #include "detection_util.h"
92 #include "profiler.h"
93 #include "hi_cmd_lookup.h"
94 #include "Unified2_common.h"
95 #include "mempool.h"
96 #include "file_mail_common.h"
97 #include "file_api.h"
98 #include "sf_email_attach_decode.h"
99 #include "file_decomp.h"
100 #include "hi_eo_log.h"
101
102 #ifdef DUMP_BUFFER
103 #include "hi_buffer_dump.h"
104 #endif
105
106 #ifdef PERF_PROFILING
107 extern PreprocStats hiDetectPerfStats;
108 extern int hiDetectCalled;
109 #endif
110
111 extern char *snort_conf_dir;
112
113 extern MemPool *hi_gzip_mempool;
114
115 extern tSfPolicyUserContextId hi_config;
116
117 extern char** xffFields;
118
119 /* Stats tracking for HTTP Inspect */
120 HIStats hi_stats;
121
122 DataBuffer HttpDecodeBuf;
123
124 const HiSearchToken hi_patterns[] =
125 {
126 {"<SCRIPT", 7, HI_JAVASCRIPT},
127 {NULL, 0, 0}
128 };
129
130 const HiSearchToken html_patterns[] =
131 {
132 {"JAVASCRIPT", 10, HTML_JS},
133 {"ECMASCRIPT", 10, HTML_EMA},
134 {"VBSCRIPT", 8, HTML_VB},
135 {NULL, 0, 0}
136 };
137
138 void *hi_javascript_search_mpse = NULL;
139 void *hi_htmltype_search_mpse = NULL;
140 HISearch hi_js_search[HI_LAST];
141 HISearch hi_html_search[HTML_LAST];
142 HISearch *hi_current_search = NULL;
143 HISearchInfo hi_search_info;
144
145
146 #define MAX_FILENAME 1000
147
148 /*
149 ** GLOBAL subkeywords.
150 */
151 /**
152 ** Takes an integer arugment
153 */
154 /**
155 ** Specifies whether to alert on anomalous
156 ** HTTP servers or not.
157 */
158 #define ANOMALOUS_SERVERS "detect_anomalous_servers"
159 /**
160 ** Alert on general proxy use
161 */
162 #define PROXY_ALERT "proxy_alert"
163 /**
164 ** Takes an inspection type argument
165 ** stateful or stateless
166 */
167 #define DEFAULT "default"
168
169 /*
170 ** SERVER subkeywords.
171 */
172 #define PORTS "ports"
173 #define FLOW_DEPTH "flow_depth"
174 #define SERVER_FLOW_DEPTH "server_flow_depth"
175 #define CLIENT_FLOW_DEPTH "client_flow_depth"
176 #define POST_DEPTH "post_depth"
177 #define IIS_UNICODE_MAP "iis_unicode_map"
178 #define CHUNK_LENGTH "chunk_length"
179 #define SMALL_CHUNK_LENGTH "small_chunk_length"
180 #define MAX_HDR_LENGTH "max_header_length"
181 #define PIPELINE "no_pipeline_req"
182 #define ASCII "ascii"
183 #define DOUBLE_DECODE "double_decode"
184 #define U_ENCODE "u_encode"
185 #define BARE_BYTE "bare_byte"
186 /* Base 36 is deprecated and essentially a noop
187 * Leave this here so as to print out a warning when the option is used */
188 #define BASE36 "base36"
189 #define UTF_8 "utf_8"
190 #define IIS_UNICODE "iis_unicode"
191 #define NON_RFC_CHAR "non_rfc_char"
192 #define MULTI_SLASH "multi_slash"
193 #define IIS_BACKSLASH "iis_backslash"
194 #define DIRECTORY "directory"
195 #define APACHE_WS "apache_whitespace"
196 #define IIS_DELIMITER "iis_delimiter"
197 #define PROFILE_STRING "profile"
198 #define NON_STRICT "non_strict"
199 #define ALLOW_PROXY "allow_proxy_use"
200 #define OVERSIZE_DIR "oversize_dir_length"
201 #define INSPECT_URI_ONLY "inspect_uri_only"
202 #define GLOBAL_ALERT "no_alerts"
203 #define WEBROOT "webroot"
204 #define TAB_URI_DELIMITER "tab_uri_delimiter"
205 #define WHITESPACE "whitespace_chars"
206 #define NORMALIZE_HEADERS "normalize_headers"
207 #define NORMALIZE_COOKIES "normalize_cookies"
208 #define NORMALIZE_UTF "normalize_utf"
209 #define NORMALIZE_JS "normalize_javascript"
210 #define MAX_JS_WS "max_javascript_whitespaces"
211 #define MAX_HEADERS "max_headers"
212 #define INSPECT_COOKIES "enable_cookie"
213 #define EXTRACT_GZIP "inspect_gzip"
214 #define UNLIMIT_DECOMPRESS "unlimited_decompress"
215 #define INSPECT_RESPONSE "extended_response_inspection"
216 #define COMPRESS_DEPTH "compress_depth"
217 #define DECOMPRESS_DEPTH "decompress_depth"
218 #define MAX_GZIP_MEM "max_gzip_mem"
219 #define EXTENDED_ASCII "extended_ascii_uri"
220 #define OPT_DISABLED "disabled"
221 #define ENABLE_XFF "enable_xff"
222 #define XFF_HEADERS_TOK "xff_headers"
223 #define HTTP_METHODS "http_methods"
224 #define LOG_URI "log_uri"
225 #define LOG_HOSTNAME "log_hostname"
226 #define HTTP_MEMCAP "memcap"
227 #define MAX_SPACES "max_spaces"
228 #define INSPECT_SWF "decompress_swf"
229 #define INSPECT_PDF "decompress_pdf"
230 #define NORMALIZE_NULLS "normalize_random_nulls_in_text"
231 #define FAST_BLOCKING "fast_blocking"
232
233 #define DECOMPRESS_DEFLATE "deflate"
234 #define DECOMPRESS_LZMA "lzma"
235 #define LEGACY_MODE "legacy_mode"
236
237 #define MAX_CLIENT_DEPTH 1460
238 #define MAX_SERVER_DEPTH 65535
239
240 /*
241 ** Alert subkeywords
242 */
243 #define BOOL_YES "yes"
244 #define BOOL_NO "no"
245
246 /*
247 ** PROFILE subkeywords
248 */
249 #define APACHE "apache"
250 #define IIS "iis"
251 #define IIS4_0 "iis4_0"
252 #define IIS5_0 "iis5_0" /* 5.0 only. For 5.1 and beyond, use IIS */
253 #define ALL "all"
254
255 /*
256 ** IP Address list delimiters
257 */
258 #define START_IPADDR_LIST "{"
259 #define END_IPADDR_LIST "}"
260
261 /*
262 ** Port list delimiters
263 */
264 #define START_PORT_LIST "{"
265 #define END_PORT_LIST "}"
266
267 /*
268 ** XFF Header list delimiters, states, etc.
269 */
270 #define START_XFF_HEADER_LIST "{"
271 #define END_XFF_HEADER_LIST "}"
272 #define START_XFF_HEADER_ENTRY "["
273 #define END_XFF_HEADER_ENTRY "]"
274
275 #define XFF_MIN_PREC (1)
276 #define XFF_MAX_PREC (255)
277
278 #define XFF_STATE_START (1)
279 #define XFF_STATE_OPEN (2)
280 #define XFF_STATE_NAME (3)
281 #define XFF_STATE_PREC (4)
282 #define XFF_STATE_CLOSE (5)
283 #define XFF_STATE_END (6)
284
285 /*
286 ** Keyword for the default server configuration
287 */
288 #define SERVER_DEFAULT "default"
289
290 typedef enum {
291 CONFIG_MAX_SPACES = 0,
292 CONFIG_MAX_JS_WS
293 } SpaceType;
294
295 typedef enum
296 {
297 CD_CHARSET_UNKNOWN,
298 CD_CHARSET_UTF8,
299 CD_CHARSET_ISO_9959_1,
300 CD_CHARSET_MIME
301 }CD_Charset;
302
303 static char** getHttpXffPrecedence(void* ssn, uint32_t flags, int* nFields);
304
305 /*
306 ** NAME
307 ** ProcessGlobalAlert::
308 */
309 /**
310 ** Process the global alert keyword.
311 **
312 ** There is no arguments to this keyword, because you can only turn
313 ** all the alerts off. As of now, we aren't going to support turning
314 ** all the alerts on.
315 **
316 ** @param GlobalConf pointer to the global configuration
317 ** @param ErrorString error string buffer
318 ** @param ErrStrLen the lenght of the error string buffer
319 **
320 ** @return an error code integer
321 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
322 **
323 ** @retval 0 successs
324 ** @retval -1 generic fatal error
325 ** @retval 1 generic non-fatal error
326 */
327 /*
328 static int ProcessGlobalAlert(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
329 char *ErrorString, int ErrStrLen)
330 {
331 GlobalConf->no_alerts = 1;
332
333 return 0;
334 }
335 */
336
337 static int ProcessIISUnicodeMap(uint8_t **iis_unicode_map,
338 char **iis_unicode_map_filename,
339 int *iis_unicode_map_codepage,
340 char *ErrorString, int ErrStrLen,
341 char **saveptr)
342 {
343 char *pcToken;
344 int iRet;
345 char filename[MAX_FILENAME];
346 char *pcEnd;
347 int iCodeMap;
348
349 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
350 if(pcToken == NULL)
351 {
352 SnortSnprintf(ErrorString, ErrStrLen,
353 "No argument to token '%s'.", IIS_UNICODE_MAP);
354
355 return -1;
356 }
357
358 /*
359 ** If an absolute path is specified, then use that.
360 */
361 #ifndef WIN32
362 if(pcToken[0] == '/')
363 {
364 iRet = SnortSnprintf(filename, sizeof(filename), "%s", pcToken);
365 }
366 else
367 {
368 /*
369 ** Set up the file name directory
370 */
371 if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '/')
372 {
373 iRet = SnortSnprintf(filename, sizeof(filename),
374 "%s%s", snort_conf_dir, pcToken);
375 }
376 else
377 {
378 iRet = SnortSnprintf(filename, sizeof(filename),
379 "%s/%s", snort_conf_dir, pcToken);
380 }
381 }
382 #else
383 if(strlen(pcToken)>3 && pcToken[1]==':' && pcToken[2]=='\\')
384 {
385 iRet = SnortSnprintf(filename, sizeof(filename), "%s", pcToken);
386 }
387 else
388 {
389 /*
390 ** Set up the file name directory
391 */
392 if (snort_conf_dir[strlen(snort_conf_dir) - 1] == '\\' ||
393 snort_conf_dir[strlen(snort_conf_dir) - 1] == '/' )
394 {
395 iRet = SnortSnprintf(filename, sizeof(filename),
396 "%s%s", snort_conf_dir, pcToken);
397 }
398 else
399 {
400 iRet = SnortSnprintf(filename, sizeof(filename),
401 "%s\\%s", snort_conf_dir, pcToken);
402 }
403 }
404 #endif
405
406 if(iRet != SNORT_SNPRINTF_SUCCESS)
407 {
408 SnortSnprintf(ErrorString, ErrStrLen,
409 "Filename too long for token '%s'.", IIS_UNICODE_MAP);
410
411 return -1;
412 }
413
414 /*
415 ** Set the filename
416 */
417 *iis_unicode_map_filename = strdup(filename);
418 if(*iis_unicode_map_filename == NULL)
419 {
420 SnortSnprintf(ErrorString, ErrStrLen,
421 "Could not strdup() '%s' filename.",
422 IIS_UNICODE_MAP);
423
424 return -1;
425 }
426
427 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
428 if(pcToken == NULL)
429 {
430 SnortSnprintf(ErrorString, ErrStrLen,
431 "No codemap to select from IIS Unicode Map file.");
432
433 return -1;
434 }
435
436 /*
437 ** Grab the unicode codemap to use
438 */
439 iCodeMap = strtol(pcToken, &pcEnd, 10);
440 if(*pcEnd || iCodeMap < 0)
441 {
442 SnortSnprintf(ErrorString, ErrStrLen,
443 "Invalid IIS codemap argument.");
444
445 return -1;
446 }
447
448 /*
449 ** Set the codepage
450 */
451 *iis_unicode_map_codepage = iCodeMap;
452
453 /*
454 ** Assume that the pcToken we now have is the filename of the map
455 ** table.
456 */
457 iRet = hi_ui_parse_iis_unicode_map(iis_unicode_map, filename, iCodeMap);
458 if (iRet)
459 {
460 if(iRet == HI_INVALID_FILE)
461 {
462 SnortSnprintf(ErrorString, ErrStrLen,
463 "Unable to open the IIS Unicode Map file '%s'.",
464 filename);
465 }
466 else if(iRet == HI_FATAL_ERR)
467 {
468 SnortSnprintf(ErrorString, ErrStrLen,
469 "Did not find specified IIS Unicode codemap in "
470 "the specified IIS Unicode Map file.");
471 }
472 else
473 {
474 SnortSnprintf(ErrorString, ErrStrLen,
475 "There was an error while parsing the IIS Unicode Map file.");
476 }
477
478 return -1;
479 }
480
481 return 0;
482 }
483
484 static int ProcessOversizeDir(HTTPINSPECT_CONF *ServerConf,
485 char *ErrorString, int ErrStrLen,
486 char **saveptr)
487 {
488 char *pcToken;
489 char *pcEnd;
490 int iDirLen;
491
492 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
493 if(pcToken == NULL)
494 {
495 SnortSnprintf(ErrorString, ErrStrLen,
496 "No argument to token '%s'.", OVERSIZE_DIR);
497
498 return -1;
499 }
500
501 /*
502 ** Grab the oversize directory length
503 */
504 iDirLen = strtol(pcToken, &pcEnd, 10);
505 if(*pcEnd || iDirLen < 0)
506 {
507 SnortSnprintf(ErrorString, ErrStrLen,
508 "Invalid argument to token '%s'.", OVERSIZE_DIR);
509
510 return -1;
511 }
512
513 ServerConf->long_dir = iDirLen;
514
515 return 0;
516 }
517
518 static int ProcessHttpMemcap(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
519 char *ErrorString, int ErrStrLen, char **saveptr)
520 {
521 char *pcToken, *pcEnd;
522 int memcap;
523
524 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
525 if(pcToken == NULL)
526 {
527 SnortSnprintf(ErrorString, ErrStrLen,
528 "No argument to '%s' token.", HTTP_MEMCAP);
529 return -1;
530 }
531
532 memcap = SnortStrtolRange(pcToken, &pcEnd, 10, 0 , INT_MAX);
533 if(*pcEnd)
534 {
535 SnortSnprintf(ErrorString, ErrStrLen,
536 "Invalid argument to '%s'.", HTTP_MEMCAP);
537
538 return -1;
539 }
540
541 if(memcap < MIN_HTTP_MEMCAP || memcap > MAX_HTTP_MEMCAP)
542 {
543 SnortSnprintf(ErrorString, ErrStrLen,
544 "Invalid argument to '%s'. Must be between %d and "
545 "%d.", HTTP_MEMCAP, MIN_HTTP_MEMCAP, MAX_HTTP_MEMCAP);
546
547 return -1;
548 }
549
550 GlobalConf->memcap = memcap;
551
552 return 0;
553
554 }
555
556
557 static int ProcessMaxGzipMem(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
558 char *ErrorString, int ErrStrLen, char **saveptr)
559 {
560 char *pcToken, *pcEnd;
561 int max_gzip_mem;
562
563 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
564 if(pcToken == NULL)
565 {
566 SnortSnprintf(ErrorString, ErrStrLen,
567 "No argument to '%s' token.", MAX_GZIP_MEM);
568 return -1;
569 }
570
571 max_gzip_mem = SnortStrtolRange(pcToken, &pcEnd, 10, 0, INT_MAX);
572 if ((pcEnd == pcToken) || *pcEnd || (errno == ERANGE))
573 {
574 SnortSnprintf(ErrorString, ErrStrLen,
575 "Invalid argument to '%s'.", MAX_GZIP_MEM);
576 return -1;
577 }
578
579 if(max_gzip_mem < GZIP_MEM_MIN)
580 {
581 SnortSnprintf(ErrorString, ErrStrLen,
582 "Invalid argument to '%s'.", MAX_GZIP_MEM);
583 return -1;
584 }
585 GlobalConf->max_gzip_mem = (unsigned int)max_gzip_mem;
586
587 return 0;
588
589 }
590
591 static int ProcessCompressDepth(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
592 char *ErrorString, int ErrStrLen, char **saveptr)
593 {
594 char *pcToken;
595 int compress_depth;
596 char *pcEnd;
597
598 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
599 if(pcToken == NULL)
600 {
601 SnortSnprintf(ErrorString, ErrStrLen,
602 "No argument to '%s' token.", COMPRESS_DEPTH);
603
604 return -1;
605 }
606
607 compress_depth = SnortStrtol(pcToken, &pcEnd, 10);
608 if(*pcEnd)
609 {
610 SnortSnprintf(ErrorString, ErrStrLen,
611 "Invalid argument to '%s'.", COMPRESS_DEPTH);
612
613 return -1;
614 }
615
616 if(compress_depth <= 0 || compress_depth > MAX_GZIP_DEPTH)
617 {
618 SnortSnprintf(ErrorString, ErrStrLen,
619 "Invalid argument to '%s'. Must be between 1 and "
620 "%d.", COMPRESS_DEPTH, MAX_GZIP_DEPTH);
621
622 return -1;
623 }
624
625 GlobalConf->compr_depth = compress_depth;
626
627 return 0;
628 }
629
630 static int ProcessDecompressDepth(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
631 char *ErrorString, int ErrStrLen, char **saveptr)
632 {
633 char *pcToken;
634 int decompress_depth;
635 char *pcEnd;
636
637 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
638 if(pcToken == NULL)
639 {
640 SnortSnprintf(ErrorString, ErrStrLen,
641 "No argument to '%s' token.", DECOMPRESS_DEPTH);
642
643 return -1;
644 }
645
646 decompress_depth = SnortStrtol(pcToken, &pcEnd, 10);
647 if(*pcEnd)
648 {
649 SnortSnprintf(ErrorString, ErrStrLen,
650 "Invalid argument to '%s'.", DECOMPRESS_DEPTH);
651
652 return -1;
653 }
654
655 if(decompress_depth <= 0 || decompress_depth > MAX_GZIP_DEPTH)
656 {
657 SnortSnprintf(ErrorString, ErrStrLen,
658 "Invalid argument to '%s'. Must be between 1 and "
659 "%d.", DECOMPRESS_DEPTH, MAX_GZIP_DEPTH);
660
661 return -1;
662 }
663
664 GlobalConf->decompr_depth = decompress_depth;
665
666 return 0;
667 }
668
669 /*
670 ** NAME
671 ** ProcessGlobalConf::
672 */
673 /**
674 ** This is where we process the global configuration for HttpInspect.
675 **
676 ** We set the values of the global configuraiton here. Any errors that
677 ** are encountered are specified in the error string and the type of
678 ** error is returned through the return code, i.e. fatal, non-fatal.
679 **
680 ** The configuration options that are dealt with here are:
681 ** - global_alert
682 ** This tells us whether to do any internal alerts or not, on
683 ** a global scale.
684 ** - max_pipeline
685 ** Tells HttpInspect how many pipeline requests to buffer looking
686 ** for a response before inspection.
687 ** - inspection_type
688 ** What type of inspection for HttpInspect to do, stateless or
689 ** stateful.
690 **
691 ** @param GlobalConf pointer to the global configuration
692 ** @param ErrorString error string buffer
693 ** @param ErrStrLen the length of the error string buffer
694 ** @param saveptr the strtok_r saved state
695 **
696 ** @return an error code integer
697 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
698 **
699 ** @retval 0 successs
700 ** @retval -1 generic fatal error
701 ** @retval 1 generic non-fatal error
702 */
703 int ProcessGlobalConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
704 char *ErrorString, int ErrStrLen, char **saveptr)
705 {
706 int iRet;
707 char *pcToken;
708 int iTokens = 0;
709
710 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
711 {
712 /*
713 ** Show that we at least got one token
714 */
715 iTokens = 1;
716
717 if(!strcmp(IIS_UNICODE_MAP, pcToken))
718 {
719 iRet = ProcessIISUnicodeMap(&GlobalConf->iis_unicode_map, &GlobalConf->iis_unicode_map_filename,
720 &GlobalConf->iis_unicode_codepage, ErrorString, ErrStrLen, saveptr);
721 if (iRet)
722 {
723 return iRet;
724 }
725 }
726 else if(!strcmp(ANOMALOUS_SERVERS, pcToken))
727 {
728 /*
729 ** This is easy to configure since we just look for the token
730 ** and turn on the option.
731 */
732 GlobalConf->anomalous_servers = 1;
733 }
734 else if(!strcmp(PROXY_ALERT, pcToken))
735 {
736 GlobalConf->proxy_alert = 1;
737 }
738 else if (!strcmp(MAX_GZIP_MEM, pcToken))
739 {
740 iRet = ProcessMaxGzipMem(GlobalConf, ErrorString, ErrStrLen, saveptr);
741 if(iRet)
742 return iRet;
743 }
744 else if (!strcmp(COMPRESS_DEPTH, pcToken))
745 {
746 iRet = ProcessCompressDepth(GlobalConf, ErrorString, ErrStrLen, saveptr);
747 if (iRet)
748 return iRet;
749 }
750 else if (!strcmp(DECOMPRESS_DEPTH, pcToken))
751 {
752 iRet = ProcessDecompressDepth(GlobalConf, ErrorString, ErrStrLen, saveptr);
753 if(iRet)
754 return iRet;
755 }
756 else if (!strcmp(OPT_DISABLED, pcToken))
757 {
758 GlobalConf->disabled = 1;
759 return 0;
760 }
761 else if (!strcmp(NORMALIZE_NULLS, pcToken))
762 {
763 GlobalConf->normalize_nulls = TRUE;
764 }
765 else if (!strcmp(FAST_BLOCKING, pcToken))
766 {
767 GlobalConf->fast_blocking = TRUE;
768 }
769
770 else if (!strcmp(HTTP_MEMCAP, pcToken))
771 {
772 iRet = ProcessHttpMemcap(GlobalConf, ErrorString, ErrStrLen, saveptr);
773 if(iRet)
774 return iRet;
775 }
776 else if (!file_api->parse_mime_decode_args(&(GlobalConf->decode_conf), pcToken, "HTTP", saveptr))
777 {
778 continue;
779 }
780 else
781 {
782 SnortSnprintf(ErrorString, ErrStrLen,
783 "Invalid keyword '%s' for '%s' configuration.",
784 pcToken, GLOBAL);
785
786 return -1;
787 }
788 }
789
790 /*
791 ** If there are not any tokens to the configuration, then
792 ** we let the user know and log the error. return non-fatal
793 ** error.
794 */
795 if(!iTokens)
796 {
797 SnortSnprintf(ErrorString, ErrStrLen,
798 "No tokens to '%s' configuration.", GLOBAL);
799
800 return -1;
801 }
802
803 /*
804 ** Let's check to make sure that we get a default IIS Unicode Codemap
805 */
806 if(!GlobalConf->iis_unicode_map)
807 {
808 SnortSnprintf(ErrorString, ErrStrLen,
809 "Global configuration must contain an IIS Unicode Map "
810 "configuration. Use token '%s'.", IIS_UNICODE_MAP);
811
812 return -1;
813 }
814
815 return 0;
816 }
817
818
819 /*
820 ** NAME
821 ** ProcessProfile::
822 */
823 /** Returns error messages for failed hi_ui_config_set_profile calls.
824 **
825 ** Called exclusively by ProcessProfile.
826 */
827 static inline int _ProcessProfileErr(int iRet, char* ErrorString,
828 int ErrStrLen, char *token)
829 {
830 if(iRet == HI_MEM_ALLOC_FAIL)
831 {
832 SnortSnprintf(ErrorString, ErrStrLen,
833 "Memory allocation failed while setting the '%s' "
834 "profile.", token);
835 return -1;
836 }
837 else
838 {
839 SnortSnprintf(ErrorString, ErrStrLen,
840 "Undefined error code for set_profile_%s.", token);
841 return -1;
842 }
843 }
844
845 /*
846 ** NAME
847 ** ProcessProfile::
848 */
849 /**
850 ** Process the PROFILE configuration.
851 **
852 ** This function verifies that the argument to the profile configuration
853 ** is valid. We also check to make sure there is no additional
854 ** configuration after the PROFILE. This is no allowed, so we
855 ** alert on that fact.
856 **
857 ** @param ServerConf pointer to the server configuration
858 ** @param ErrorString error string buffer
859 ** @param ErrStrLen the length of the error string buffer
860 ** @param saveptr the strtok_r saved state
861 **
862 ** @return an error code integer
863 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
864 **
865 ** @retval 0 successs
866 ** @retval -1 generic fatal error
867 ** @retval 1 generic non-fatal error
868 */
869 static int ProcessProfile(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
870 HTTPINSPECT_CONF *ServerConf,
871 char *ErrorString, int ErrStrLen,
872 char **saveptr)
873 {
874 char *pcToken;
875 int iRet;
876
877 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
878 if(pcToken == NULL)
879 {
880 SnortSnprintf(ErrorString, ErrStrLen,
881 "No argument to '%s'.", PROFILE_STRING);
882
883 return -1;
884 }
885
886 /*
887 ** Load the specific type of profile
888 */
889 if(!strcmp(APACHE, pcToken))
890 {
891 iRet = hi_ui_config_set_profile_apache(ServerConf);
892 if (iRet)
893 {
894 /* returns -1 */
895 return _ProcessProfileErr(iRet, ErrorString, ErrStrLen, pcToken);
896 }
897
898 ServerConf->profile = HI_APACHE;
899 }
900 else if(!strcmp(IIS, pcToken))
901 {
902 iRet = hi_ui_config_set_profile_iis(ServerConf, GlobalConf->iis_unicode_map);
903 if (iRet)
904 {
905 /* returns -1 */
906 return _ProcessProfileErr(iRet, ErrorString, ErrStrLen, pcToken);
907 }
908
909 ServerConf->profile = HI_IIS;
910 }
911 else if(!strcmp(IIS4_0, pcToken) || !strcmp(IIS5_0, pcToken))
912 {
913 iRet = hi_ui_config_set_profile_iis_4or5(ServerConf, GlobalConf->iis_unicode_map);
914 if (iRet)
915 {
916 /* returns -1 */
917 return _ProcessProfileErr(iRet, ErrorString, ErrStrLen, pcToken);
918 }
919
920 ServerConf->profile = (pcToken[3]=='4'?HI_IIS4:HI_IIS5);
921 }
922 else if(!strcmp(ALL, pcToken))
923 {
924 iRet = hi_ui_config_set_profile_all(ServerConf, GlobalConf->iis_unicode_map);
925 if (iRet)
926 {
927 /* returns -1 */
928 return _ProcessProfileErr(iRet, ErrorString, ErrStrLen, pcToken);
929 }
930
931 ServerConf->profile = HI_ALL;
932 }
933 else
934 {
935 SnortSnprintf(ErrorString, ErrStrLen,
936 "Invalid profile argument '%s'.", pcToken);
937
938 return -1;
939 }
940
941 return 0;
942
943
944 }
945
946 /*
947 ** NAME
948 ** ProcessPorts::
949 */
950 /**
951 ** Process the port list for the server configuration.
952 **
953 ** This configuration is a list of valid ports and is ended by a
954 ** delimiter.
955 **
956 ** @param ServerConf pointer to the server configuration
957 ** @param ErrorString error string buffer
958 ** @param ErrStrLen the length of the error string buffer
959 ** @param saveptr the strtok_r saved state
960 **
961 ** @return an error code integer
962 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
963 **
964 ** @retval 0 successs
965 ** @retval -1 generic fatal error
966 ** @retval 1 generic non-fatal error
967 */
968 static int ProcessPorts(HTTPINSPECT_CONF *ServerConf,
969 char *ErrorString, int ErrStrLen, char **saveptr)
970 {
971 char *pcToken;
972 char *pcEnd;
973 int iPort;
974 int iEndPorts = 0;
975
976 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
977 if(!pcToken)
978 {
979 SnortSnprintf(ErrorString, ErrStrLen,
980 "Invalid port list format.");
981
982 return -1;
983 }
984
985 if(strcmp(START_PORT_LIST, pcToken))
986 {
987 SnortSnprintf(ErrorString, ErrStrLen,
988 "Must start a port list with the '%s' token.",
989 START_PORT_LIST);
990
991 return -1;
992 }
993
994 memset(ServerConf->ports, 0, MAXPORTS_STORAGE);
995
996 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
997 {
998 if(!strcmp(END_PORT_LIST, pcToken))
999 {
1000 iEndPorts = 1;
1001 break;
1002 }
1003
1004 iPort = strtol(pcToken, &pcEnd, 10);
1005
1006 /*
1007 ** Validity check for port
1008 */
1009 if(*pcEnd)
1010 {
1011 SnortSnprintf(ErrorString, ErrStrLen, "Invalid port number.");
1012
1013 return -1;
1014 }
1015
1016 if(iPort < 0 || iPort > MAXPORTS-1)
1017 {
1018 SnortSnprintf(ErrorString, ErrStrLen,
1019 "Invalid port number. Must be between 0 and 65535.");
1020
1021 return -1;
1022 }
1023
1024 enablePort( ServerConf->ports, iPort );
1025
1026 if(ServerConf->port_count < MAXPORTS)
1027 ServerConf->port_count++;
1028 }
1029
1030 if(!iEndPorts)
1031 {
1032 SnortSnprintf(ErrorString, ErrStrLen,
1033 "Must end '%s' configuration with '%s'.",
1034 PORTS, END_PORT_LIST);
1035
1036 return -1;
1037 }
1038
1039 return 0;
1040 }
1041
1042 /*
1043 ** NAME
1044 ** ProcessFlowDepth::
1045 */
1046 /**
1047 ** Configure the flow depth for a server.
1048 **
1049 ** Check that the value for flow depth is within bounds
1050 ** and is a valid number.
1051 **
1052 ** @param ServerConf pointer to the server configuration
1053 ** @param ServerOrClient which flowdepth is being set
1054 ** @param ErrorString error string buffer
1055 ** @param ErrStrLen the length of the error string buffer
1056 ** @param saveptr the strtok_r saved state
1057 **
1058 ** @return an error code integer
1059 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1060 **
1061 ** @retval 0 successs
1062 ** @retval -1 generic fatal error
1063 ** @retval 1 generic non-fatal error
1064 */
1065 static int ProcessFlowDepth(HTTPINSPECT_CONF *ServerConf, int ServerOrClient,
1066 char *ErrorString, int ErrStrLen, char **saveptr, char *pToken, int maxDepth)
1067 {
1068 char *pcToken;
1069 int iFlowDepth;
1070 char *pcEnd;
1071
1072 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1073 if(pcToken == NULL)
1074 {
1075 SnortSnprintf(ErrorString, ErrStrLen,
1076 "No argument to '%s' token.", pToken);
1077
1078 return -1;
1079 }
1080
1081 iFlowDepth = SnortStrtol(pcToken, &pcEnd, 10);
1082 if(*pcEnd)
1083 {
1084 SnortSnprintf(ErrorString, ErrStrLen,
1085 "Invalid argument to '%s'.", pToken);
1086
1087 return -1;
1088 }
1089
1090 /* -1 here is okay, which means ignore ALL server side traffic */
1091 if(iFlowDepth < -1 || iFlowDepth > maxDepth)
1092 {
1093 SnortSnprintf(ErrorString, ErrStrLen,
1094 "Invalid argument to '%s'. Must be between -1 and %d.",
1095 pToken, maxDepth);
1096
1097 return -1;
1098 }
1099
1100 if (ServerOrClient == HI_SI_CLIENT_MODE)
1101 ServerConf->client_flow_depth = iFlowDepth;
1102 else
1103 ServerConf->server_flow_depth = iFlowDepth;
1104
1105 return 0;
1106 }
1107
1108 /*
1109 ** NAME
1110 ** ProcessPostDepth::
1111 */
1112 /**
1113 ** Configure the post depth for client requests
1114 **
1115 ** Checks that the value for flow depth is within bounds
1116 ** and is a valid number.
1117 **
1118 ** @param ServerConf pointer to the server configuration
1119 ** @param ErrorString error string buffer
1120 ** @param ErrStrLen the length of the error string buffer
1121 ** @param saveptr the strtok_r saved state
1122 **
1123 ** @return an error code integer
1124 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1125 **
1126 ** @retval 0 successs
1127 ** @retval -1 generic fatal error
1128 ** @retval 1 generic non-fatal error
1129 */
1130 static int ProcessPostDepth(HTTPINSPECT_CONF *ServerConf,
1131 char *ErrorString, int ErrStrLen, char **saveptr)
1132 {
1133 char *pcToken;
1134 int post_depth;
1135 char *pcEnd;
1136
1137 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1138 if(pcToken == NULL)
1139 {
1140 SnortSnprintf(ErrorString, ErrStrLen,
1141 "No argument to '%s' token.", POST_DEPTH);
1142
1143 return -1;
1144 }
1145
1146 post_depth = SnortStrtol(pcToken, &pcEnd, 10);
1147 if(*pcEnd)
1148 {
1149 SnortSnprintf(ErrorString, ErrStrLen,
1150 "Invalid argument to '%s'.", POST_DEPTH);
1151
1152 return -1;
1153 }
1154
1155 /* 0 means 'any depth' */
1156 if(post_depth < -1 || post_depth > ( IP_MAXPACKET - (IP_HEADER_LEN + TCP_HEADER_LEN) ) )
1157 {
1158 SnortSnprintf(ErrorString, ErrStrLen,
1159 "Invalid argument to '%s'. Must be between -1 and "
1160 "%d.", POST_DEPTH,( IP_MAXPACKET - (IP_HEADER_LEN + TCP_HEADER_LEN) ));
1161
1162 return -1;
1163 }
1164
1165 ServerConf->post_depth = post_depth;
1166
1167 return 0;
1168 }
1169
1170
1171 /*
1172 ** NAME
1173 ** ProcessChunkLength::
1174 */
1175 /**
1176 ** Process and verify the chunk length for the server configuration.
1177 **
1178 ** @param ServerConf pointer to the server configuration
1179 ** @param ErrorString error string buffer
1180 ** @param ErrStrLen the length of the error string buffer
1181 ** @param saveptr the strtok_r saved state
1182 **
1183 ** @return an error code integer
1184 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1185 **
1186 ** @retval 0 successs
1187 ** @retval -1 generic fatal error
1188 ** @retval 1 generic non-fatal error
1189 */
1190 static int ProcessChunkLength(HTTPINSPECT_CONF *ServerConf,
1191 char *ErrorString, int ErrStrLen, char **saveptr)
1192 {
1193 char *pcToken;
1194 int iChunkLength;
1195 char *pcEnd;
1196
1197 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1198 if(pcToken == NULL)
1199 {
1200 SnortSnprintf(ErrorString, ErrStrLen,
1201 "No argument to '%s' token.", CHUNK_LENGTH);
1202
1203 return -1;
1204 }
1205
1206 iChunkLength = SnortStrtolRange(pcToken, &pcEnd, 10, 0, INT_MAX);
1207 if ((pcEnd == pcToken) || *pcEnd || (errno == ERANGE))
1208 {
1209 SnortSnprintf(ErrorString, ErrStrLen,
1210 "Invalid argument to '%s'.", CHUNK_LENGTH);
1211
1212 return -1;
1213 }
1214
1215 ServerConf->chunk_length = iChunkLength;
1216
1217 return 0;
1218 }
1219
1220 /*
1221 ** NAME
1222 ** ProcessSmallChunkLength::
1223 */
1224 /**
1225 ** Process and verify the small chunk length for the server configuration.
1226 **
1227 ** @param ServerConf pointer to the server configuration
1228 ** @param ErrorString error string buffer
1229 ** @param ErrStrLen the length of the error string buffer
1230 ** @param saveptr the strtok_r saved state
1231 **
1232 ** @return an error code integer
1233 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1234 **
1235 ** @retval 0 successs
1236 ** @retval -1 generic fatal error
1237 ** @retval 1 generic non-fatal error
1238 */
1239 static int ProcessSmallChunkLength(HTTPINSPECT_CONF *ServerConf,
1240 char *ErrorString, int ErrStrLen, char **saveptr)
1241 {
1242 char *pcToken;
1243 char *pcEnd;
1244 int num_toks = 0;
1245 bool got_param_end = 0;
1246
1247 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1248 if (!pcToken)
1249 {
1250 SnortSnprintf(ErrorString, ErrStrLen,
1251 "Invalid cmd list format.");
1252
1253 return -1;
1254 }
1255
1256 if (strcmp(START_PORT_LIST, pcToken))
1257 {
1258 SnortSnprintf(ErrorString, ErrStrLen,
1259 "Must start small chunk length parameters with the '%s' token.",
1260 START_PORT_LIST);
1261
1262 return -1;
1263 }
1264
1265 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
1266 {
1267 if (!strcmp(END_PORT_LIST, pcToken))
1268 {
1269 got_param_end = 1;
1270 break;
1271 }
1272
1273 num_toks++;
1274 if (num_toks > 2)
1275 {
1276 SnortSnprintf(ErrorString, ErrStrLen,
1277 "Too many arguments to '%s'.", SMALL_CHUNK_LENGTH);
1278
1279 return -1;
1280 }
1281
1282 if (num_toks == 1)
1283 {
1284 uint32_t chunk_length = (uint32_t)SnortStrtoulRange(pcToken, &pcEnd, 10, 0, UINT8_MAX);
1285 if ((pcEnd == pcToken) || *pcEnd || (errno == ERANGE))
1286 {
1287 SnortSnprintf(ErrorString, ErrStrLen,
1288 "Invalid argument to chunk length param of '%s'. "
1289 "Must be between 0 and %u.\n",
1290 SMALL_CHUNK_LENGTH, UINT8_MAX);
1291
1292 return -1;
1293 }
1294
1295 ServerConf->small_chunk_length.size = (uint8_t)chunk_length;
1296 }
1297 else
1298 {
1299 uint32_t num_chunks_threshold = (uint32_t)SnortStrtoulRange(pcToken, &pcEnd, 10, 0, UINT8_MAX);
1300 if ((pcEnd == pcToken) || *pcEnd || (errno == ERANGE))
1301 {
1302 SnortSnprintf(ErrorString, ErrStrLen,
1303 "Invalid argument to number of consecutive chunks "
1304 "threshold of '%s'. Must be between 0 and %u.\n",
1305 SMALL_CHUNK_LENGTH, UINT8_MAX);
1306
1307 return -1;
1308 }
1309
1310 ServerConf->small_chunk_length.num = (uint8_t)num_chunks_threshold;
1311 }
1312 }
1313
1314 if (num_toks != 2)
1315 {
1316 SnortSnprintf(ErrorString, ErrStrLen,
1317 "Not enough arguments to '%s'.", SMALL_CHUNK_LENGTH);
1318
1319 return -1;
1320 }
1321
1322 if (!got_param_end)
1323 {
1324 SnortSnprintf(ErrorString, ErrStrLen,
1325 "Must end '%s' configuration with '%s'.", SMALL_CHUNK_LENGTH, END_PORT_LIST);
1326
1327 return -1;
1328 }
1329
1330 return 0;
1331 }
1332
1333 /*
1334 ** NAME
1335 ** ProcessMaxHeaders::
1336 */
1337 /**
1338 ** Process and verify the maximum allowed number of headers for the
1339 ** server configuration.
1340 **
1341 ** @param ServerConf pointer to the server configuration
1342 ** @param ErrorString error string buffer
1343 ** @param ErrStrLen the length of the error string buffer
1344 ** @param saveptr the strtok_r saved state
1345 **
1346 ** @return an error code integer
1347 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1348 **
1349 ** @retval 0 successs
1350 ** @retval -1 generic fatal error
1351 ** @retval 1 generic non-fatal error
1352 */
1353 static int ProcessMaxHeaders(HTTPINSPECT_CONF *ServerConf,
1354 char *ErrorString, int ErrStrLen, char **saveptr)
1355 {
1356 char *pcToken;
1357 int length;
1358 char *pcEnd;
1359
1360 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1361 if(pcToken == NULL)
1362 {
1363 SnortSnprintf(ErrorString, ErrStrLen,
1364 "No argument to '%s' token.", MAX_HEADERS);
1365
1366 return -1;
1367 }
1368
1369 length = strtol(pcToken, &pcEnd, 10);
1370 if(*pcEnd || pcEnd == pcToken)
1371 {
1372 SnortSnprintf(ErrorString, ErrStrLen,
1373 "Invalid argument to '%s'.", MAX_HEADERS);
1374
1375 return -1;
1376 }
1377
1378 if(length < 0)
1379 {
1380 SnortSnprintf(ErrorString, ErrStrLen,
1381 "Invalid argument to '%s'. Valid range is 0 to 1024.", MAX_HEADERS);
1382
1383 return -1;
1384 }
1385
1386 if(length > 1024)
1387 {
1388 SnortSnprintf(ErrorString, ErrStrLen,
1389 "Invalid argument to '%s'. Valid range is 0 to 1024.", MAX_HEADERS);
1390
1391 return -1;
1392 }
1393
1394 ServerConf->max_headers = length;
1395
1396 return 0;
1397 }
1398
1399 /*
1400 ** NAME
1401 ** ProcessMaxHdrLen::
1402 */
1403 /**
1404 ** Process and verify the maximum allowed header length for the
1405 ** server configuration.
1406 **
1407 ** @param ServerConf pointer to the server configuration
1408 ** @param ErrorString error string buffer
1409 ** @param ErrStrLen the length of the error string buffer
1410 ** @param saveptr the strtok_r saved state
1411 **
1412 ** @return an error code integer
1413 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1414 **
1415 ** @retval 0 successs
1416 ** @retval -1 generic fatal error
1417 ** @retval 1 generic non-fatal error
1418 */
1419 static int ProcessMaxHdrLen(HTTPINSPECT_CONF *ServerConf,
1420 char *ErrorString, int ErrStrLen, char **saveptr)
1421 {
1422 char *pcToken;
1423 int length;
1424 char *pcEnd;
1425
1426 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1427 if(pcToken == NULL)
1428 {
1429 SnortSnprintf(ErrorString, ErrStrLen,
1430 "No argument to '%s' token.", MAX_HDR_LENGTH);
1431
1432 return -1;
1433 }
1434
1435 length = strtol(pcToken, &pcEnd, 10);
1436 if(*pcEnd || pcEnd == pcToken)
1437 {
1438 SnortSnprintf(ErrorString, ErrStrLen,
1439 "Invalid argument to '%s'.", MAX_HDR_LENGTH);
1440
1441 return -1;
1442 }
1443
1444 if(length < 0)
1445 {
1446 SnortSnprintf(ErrorString, ErrStrLen,
1447 "Invalid argument to '%s'. Valid range is 0 to 65535.", MAX_HDR_LENGTH);
1448
1449 return -1;
1450 }
1451
1452 if(length > 65535)
1453 {
1454 SnortSnprintf(ErrorString, ErrStrLen,
1455 "Invalid argument to '%s'. Valid range is 0 to 65535.", MAX_HDR_LENGTH);
1456
1457 return -1;
1458 }
1459
1460 ServerConf->max_hdr_len = length;
1461
1462 return 0;
1463 }
1464
1465 /*
1466 ** NAME
1467 ** ProcessConfOpt::
1468 */
1469 /**
1470 ** Set the CONF_OPT on and alert fields.
1471 **
1472 ** We check to make sure of valid parameters and then
1473 ** set the appropriate fields. Not much more to it, than
1474 ** that.
1475 **
1476 ** @param ConfOpt pointer to the configuration option
1477 ** @param Option character pointer to the option being configured
1478 ** @param ErrorString error string buffer
1479 ** @param ErrStrLen the length of the error string buffer
1480 ** @param saveptr the strtok_r saved state
1481 **
1482 ** @return an error code integer
1483 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1484 **
1485 ** @retval 0 successs
1486 ** @retval -1 generic fatal error
1487 ** @retval 1 generic non-fatal error
1488 */
1489 static int ProcessConfOpt(HTTPINSPECT_CONF_OPT *ConfOpt, char *Option,
1490 char *ErrorString, int ErrStrLen, char **saveptr)
1491 {
1492 char *pcToken;
1493
1494 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1495 if(pcToken == NULL)
1496 {
1497 SnortSnprintf(ErrorString, ErrStrLen,
1498 "No argument to token '%s'.", Option);
1499
1500 return -1;
1501 }
1502
1503 /*
1504 ** Check for the alert value
1505 */
1506 if(!strcmp(BOOL_YES, pcToken))
1507 {
1508 ConfOpt->alert = 1;
1509 }
1510 else if(!strcmp(BOOL_NO, pcToken))
1511 {
1512 ConfOpt->alert = 0;
1513 }
1514 else
1515 {
1516 SnortSnprintf(ErrorString, ErrStrLen,
1517 "Invalid argument to token '%s'.", Option);
1518
1519 return -1;
1520 }
1521
1522 ConfOpt->on = 1;
1523
1524 return 0;
1525 }
1526
1527 /*
1528 ** NAME
1529 ** ProcessNonRfcChar::
1530 */
1531 /***
1532 ** Configure any characters that the user wants alerted on in the
1533 ** URI.
1534 **
1535 ** This function allocates the memory for CONF_OPT per character and
1536 ** configures the alert option.
1537 **
1538 ** @param ConfOpt pointer to the configuration option
1539 ** @param ErrorString error string buffer
1540 ** @param ErrStrLen the length of the error string buffer
1541 ** @param saveptr the strtok_r saved state
1542 **
1543 ** @return an error code integer
1544 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1545 **
1546 ** @retval 0 successs
1547 ** @retval -1 generic fatal error
1548 ** @retval 1 generic non-fatal error
1549 */
1550 static int ProcessNonRfcChar(HTTPINSPECT_CONF *ServerConf,
1551 char *ErrorString, int ErrStrLen, char **saveptr)
1552 {
1553 char *pcToken;
1554 char *pcEnd;
1555 int iChar;
1556 int iEndChar = 0;
1557
1558 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1559 if(!pcToken)
1560 {
1561 SnortSnprintf(ErrorString, ErrStrLen,
1562 "Invalid '%s' list format.", NON_RFC_CHAR);
1563
1564 return -1;
1565 }
1566
1567 if(strcmp(START_PORT_LIST, pcToken))
1568 {
1569 SnortSnprintf(ErrorString, ErrStrLen,
1570 "Must start a '%s' list with the '%s' token.",
1571 NON_RFC_CHAR, START_PORT_LIST);
1572
1573 return -1;
1574 }
1575
1576 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
1577 {
1578 if(!strcmp(END_PORT_LIST, pcToken))
1579 {
1580 iEndChar = 1;
1581 break;
1582 }
1583
1584 iChar = strtol(pcToken, &pcEnd, 16);
1585 if(*pcEnd)
1586 {
1587 SnortSnprintf(ErrorString, ErrStrLen,
1588 "Invalid argument to '%s'. Must be a single character.",
1589 NON_RFC_CHAR);
1590
1591 return -1;
1592 }
1593
1594 if(iChar < 0 || iChar > 255)
1595 {
1596 SnortSnprintf(ErrorString, ErrStrLen,
1597 "Invalid character value to '%s'. Must be a single "
1598 "character no greater than 255.", NON_RFC_CHAR);
1599
1600 return -1;
1601 }
1602
1603 ServerConf->non_rfc_chars[iChar] = 1;
1604 }
1605
1606 if(!iEndChar)
1607 {
1608 SnortSnprintf(ErrorString, ErrStrLen,
1609 "Must end '%s' configuration with '%s'.",
1610 NON_RFC_CHAR, END_PORT_LIST);
1611
1612 return -1;
1613 }
1614
1615 return 0;
1616 }
1617
1618 /*
1619 ** NAME
1620 ** ProcessWhitespaceChars::
1621 */
1622 /***
1623 ** Configure any characters that the user wants to be treated as
1624 ** whitespace characters before and after a URI.
1625 **
1626 **
1627 ** @param ServerConf pointer to the server configuration structure
1628 ** @param ErrorString error string buffer
1629 ** @param ErrStrLen the length of the error string buffer
1630 ** @param saveptr the strtok_r saved state
1631 **
1632 ** @return an error code integer
1633 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
1634 **
1635 ** @retval 0 successs
1636 ** @retval -1 generic fatal error
1637 ** @retval 1 generic non-fatal error
1638 */
1639 static int ProcessWhitespaceChars(HTTPINSPECT_CONF *ServerConf,
1640 char *ErrorString, int ErrStrLen, char **saveptr)
1641 {
1642 char *pcToken;
1643 char *pcEnd;
1644 int iChar;
1645 int iEndChar = 0;
1646
1647 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1648 if(!pcToken)
1649 {
1650 SnortSnprintf(ErrorString, ErrStrLen,
1651 "Invalid '%s' list format.", WHITESPACE);
1652
1653 return -1;
1654 }
1655
1656 if(strcmp(START_PORT_LIST, pcToken))
1657 {
1658 SnortSnprintf(ErrorString, ErrStrLen,
1659 "Must start a '%s' list with the '%s' token.",
1660 WHITESPACE, START_PORT_LIST);
1661
1662 return -1;
1663 }
1664
1665 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
1666 {
1667 if(!strcmp(END_PORT_LIST, pcToken))
1668 {
1669 iEndChar = 1;
1670 break;
1671 }
1672
1673 iChar = strtol(pcToken, &pcEnd, 16);
1674 if(*pcEnd)
1675 {
1676 SnortSnprintf(ErrorString, ErrStrLen,
1677 "Invalid argument to '%s'. Must be a single character.",
1678 WHITESPACE);
1679
1680 return -1;
1681 }
1682
1683 if(iChar < 0 || iChar > 255)
1684 {
1685 SnortSnprintf(ErrorString, ErrStrLen,
1686 "Invalid character value to '%s'. Must be a single "
1687 "character no greater than 255.", WHITESPACE);
1688
1689 return -1;
1690 }
1691
1692 ServerConf->whitespace[iChar] = HI_UI_CONFIG_WS_BEFORE_URI;
1693 }
1694
1695 if(!iEndChar)
1696 {
1697 SnortSnprintf(ErrorString, ErrStrLen,
1698 "Must end '%s' configuration with '%s'.",
1699 WHITESPACE, END_PORT_LIST);
1700
1701 return -1;
1702 }
1703
1704 return 0;
1705 }
1706
1707 static bool Is_Field_Prec_Unique( uint8_t *Name_Array[], uint8_t Prec_Array[],
1708 uint8_t *Name, uint8_t Precedence,
1709 char *ErrorString, int ErrStrLen )
1710 {
1711 int i;
1712
1713 for( i=0; i<HTTP_MAX_XFF_FIELDS; i++ )
1714 {
1715 /* A NULL entry indicates the end of the list */
1716 if( Name_Array[i] == NULL )
1717 break;
1718
1719 if( strcmp( (char *)Name, (char *)Name_Array[i] ) == 0 )
1720 {
1721 SnortSnprintf(ErrorString, ErrStrLen,
1722 "Duplicate XFF Field name: %s.", Name);
1723
1724 return( false );
1725 }
1726
1727 if( (Precedence != 0) && (Precedence == Prec_Array[i]) )
1728 {
1729 SnortSnprintf(ErrorString, ErrStrLen,
1730 "Duplicate XFF Precedence value: %u.", Precedence);
1731
1732 return( false );
1733 }
1734 }
1735 return( true );
1736 }
1737
1738 static int Find_Open_Field( uint8_t *Name_Array[] )
1739 {
1740 int i;
1741
1742 for( i=0; i<HTTP_MAX_XFF_FIELDS; i++ )
1743 if( Name_Array[i] == NULL )
1744 return( i );
1745 return( -1 );
1746 }
1747
1748 static void Push_Down_XFF_List( uint8_t *Name_Array[], uint8_t *Length_Array, uint8_t Prec_Array[], int Start )
1749 {
1750 int i;
1751
1752 for( i=(HTTP_MAX_XFF_FIELDS-1); i>=Start; i-- )
1753 {
1754 Name_Array[i] = Name_Array[i-1];
1755 Length_Array[i] = Length_Array[i-1];
1756 Prec_Array[i] = Prec_Array[i-1];
1757 }
1758 }
1759
1760 /* The caller of Add_XFF_Field is responsible for determining that at least one
1761 additional entry is availble in both the field name array and the precedence
1762 value array. */
1763 static int Add_XFF_Field( HTTPINSPECT_CONF *ServerConf, uint8_t *Prec_Array, uint8_t *Field_Name,
1764 uint8_t Precedence, char *ErrorString, int ErrStrLen )
1765 {
1766 uint8_t **Fields = ServerConf->xff_headers;
1767 uint8_t *Lengths = ServerConf->xff_header_lengths;
1768 size_t Length = 0;
1769 int i;
1770 char **Builtin_Fields;
1771 unsigned char *cp;
1772 const char *Special_Chars = { "_-" };
1773 bool fieldAdded = false;
1774
1775 if(!Field_Name )
1776 {
1777 SnortSnprintf(ErrorString, ErrStrLen,
1778 "Field name is null" );
1779 return -1;
1780 }
1781
1782 if( (Length = strlen( (char *)Field_Name )) > UINT8_MAX )
1783 {
1784 SnortSnprintf(ErrorString, ErrStrLen,
1785 "Field name limited to %u characters", UINT8_MAX);
1786 return -1;
1787 }
1788
1789 cp = (unsigned char*)Field_Name;
1790 while( *cp != '\0' )
1791 {
1792 *cp = (uint8_t)toupper(*cp); // Fold to upper case for runtime comparisons
1793 if( (isalnum( *cp ) == 0) && (strchr( Special_Chars, (int)(*cp) ) == NULL) )
1794 {
1795 SnortSnprintf(ErrorString, ErrStrLen,
1796 "Invalid xff field name: %s ", Field_Name);
1797 return( -1 );
1798 }
1799 cp += 1;
1800 }
1801
1802 Builtin_Fields = hi_client_get_field_names();
1803 for( i=0; Builtin_Fields[i]!=NULL; i++ )
1804 {
1805 if( strcasecmp(Builtin_Fields[i], HTTP_XFF_FIELD_X_FORWARDED_FOR) == 0 ) continue;
1806 if( strcasecmp(Builtin_Fields[i], HTTP_XFF_FIELD_TRUE_CLIENT_IP) == 0 ) continue;
1807 if( strcasecmp(Builtin_Fields[i], (char *)Field_Name) == 0 )
1808 {
1809 SnortSnprintf(ErrorString, ErrStrLen,
1810 "Cannot use: '%s' as an xff header.", Field_Name);
1811 return -1;
1812 }
1813 }
1814
1815 if( !Is_Field_Prec_Unique( Fields, Prec_Array, Field_Name, Precedence,
1816 ErrorString, ErrStrLen ) )
1817 return( -1 );
1818
1819 if( Precedence == 0 )
1820 {
1821 if( (i = Find_Open_Field( Fields )) >= 0 )
1822 {
1823 Fields[i] = Field_Name;
1824 Lengths[i] = (uint8_t)Length;
1825 Prec_Array[i] = 0;
1826 fieldAdded = true;
1827 }
1828 else
1829 return( -1 );
1830 }
1831 else
1832 {
1833 for( i=0; i<HTTP_MAX_XFF_FIELDS; i++ )
1834 {
1835 /* If the space is open, place the name & prec */
1836 if( Fields[i] == NULL )
1837 {
1838 Fields[i] = Field_Name;
1839 Lengths[i] = (uint8_t)Length;
1840 Prec_Array[i] = Precedence;
1841 fieldAdded = true;
1842 break;
1843 }
1844
1845 /* if the new entry is higher precedence than the current list element,
1846 push the list down and place the new entry here. */
1847 if( Precedence < Prec_Array[i] )
1848 {
1849 Push_Down_XFF_List( Fields, Lengths, Prec_Array, i+1 );
1850 Fields[i] = Field_Name;
1851 Lengths[i] = (uint8_t)Length;
1852 Prec_Array[i] = Precedence;
1853 fieldAdded = true;
1854 break;
1855 }
1856 }
1857 }
1858
1859 if (fieldAdded)
1860 {
1861 for (i = 0; i < HTTP_MAX_XFF_FIELDS; i++)
1862 {
1863 if (!xffFields[i])
1864 {
1865 xffFields[i] = SnortStrndup((char *)Field_Name, UINT8_MAX);
1866 break;
1867 }
1868 else if (!strncasecmp(xffFields[i], (char *)Field_Name, UINT8_MAX)) break;
1869 }
1870 }
1871
1872 return( 0 );
1873 }
1874
1875 static int ProcessXFF_HeaderList(HTTPINSPECT_CONF *ServerConf,
1876 char *ErrorString, int ErrStrLen, char **saveptr)
1877 {
1878 char *pcToken;
1879 int Parse_State;
1880 bool Keep_Parsing = false;
1881 bool Have_XFF = false;
1882 bool Have_TCI = false;
1883 uint8_t Prec_List[HTTP_MAX_XFF_FIELDS];
1884 unsigned char Count = 0;
1885 unsigned char Max_XFF = { (HTTP_MAX_XFF_FIELDS-HTTP_XFF_BUILTIN_NAMES) };
1886 uint8_t *Field_Name=NULL;
1887 unsigned int Precedence;
1888 int i;
1889 uint8_t addXffFieldName = 0;
1890
1891 /* NOTE: This procedure assumes that the ServerConf->xff_headers array
1892 contains all NULL's due to the structure allocation process. */
1893
1894 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
1895 if(!pcToken)
1896 {
1897 SnortSnprintf(ErrorString, ErrStrLen,
1898 "Invalid XFF list format.");
1899
1900 return -1;
1901 }
1902
1903 for( i=0; i<HTTP_MAX_XFF_FIELDS; i++ ) Prec_List[i] = 0;
1904 Parse_State = XFF_STATE_START;
1905 Keep_Parsing = true;
1906
1907 do
1908 {
1909 switch( Parse_State )
1910 {
1911 case( XFF_STATE_START ):
1912 {
1913 if( strcmp( START_XFF_HEADER_LIST, pcToken ) != 0 )
1914 {
1915 SnortSnprintf(ErrorString, ErrStrLen,
1916 "Must start an xff header list with the '%s' token.",
1917 START_XFF_HEADER_LIST);
1918 return( -1 );
1919 }
1920 Parse_State = XFF_STATE_OPEN;
1921 break;
1922 }
1923 case( XFF_STATE_OPEN ):
1924 {
1925 if( strcmp( START_XFF_HEADER_ENTRY, pcToken ) == 0 )
1926 Parse_State = XFF_STATE_NAME;
1927 else if( strcmp( END_XFF_HEADER_LIST, pcToken ) == 0 )
1928 {
1929 Parse_State = XFF_STATE_END;
1930 Keep_Parsing = false;
1931 }
1932 else
1933 {
1934 SnortSnprintf(ErrorString, ErrStrLen,
1935 "xff header parsing error");
1936 return( -1 );
1937 }
1938 break;
1939 }
1940 case( XFF_STATE_NAME ):
1941 {
1942 Field_Name = (uint8_t *)SnortStrdup( pcToken );
1943 Parse_State = XFF_STATE_PREC;
1944 break;
1945 }
1946 case( XFF_STATE_PREC ):
1947 {
1948 Precedence = xatou( pcToken, "Precedence" );
1949
1950 if( (Precedence > XFF_MAX_PREC) || (Precedence < XFF_MIN_PREC) )
1951 {
1952 SnortSnprintf(ErrorString, ErrStrLen,
1953 "illegal precendence value: %u", Precedence);
1954 if( Field_Name )
1955 free(Field_Name);
1956 return( -1 );
1957 }
1958
1959 if( strcasecmp( (char *)Field_Name, HTTP_XFF_FIELD_X_FORWARDED_FOR) == 0 )
1960 {
1961 Max_XFF += 1;
1962 Have_XFF = true;
1963 }
1964 else if( strcasecmp( (char *)Field_Name, HTTP_XFF_FIELD_TRUE_CLIENT_IP) == 0 )
1965 {
1966 Max_XFF += 1;
1967 Have_TCI = true;
1968 }
1969 else
1970 Count += 1;
1971
1972 if( Count > Max_XFF )
1973 {
1974 SnortSnprintf(ErrorString, ErrStrLen,
1975 "too many xff field names");
1976 if( Field_Name )
1977 free(Field_Name);
1978 return( -1 );
1979 }
1980
1981 if( Add_XFF_Field( ServerConf, Prec_List, Field_Name, (uint8_t)Precedence,
1982 ErrorString, ErrStrLen ) != 0 )
1983 {
1984 SnortSnprintf(ErrorString, ErrStrLen,
1985 "Error adding xff header: %s", Field_Name);
1986 if( Field_Name )
1987 free(Field_Name);
1988 return( -1 );
1989 }
1990 addXffFieldName = 1;
1991 Parse_State = XFF_STATE_CLOSE;
1992 break;
1993 }
1994 case( XFF_STATE_CLOSE ):
1995 {
1996 if( strcmp( END_XFF_HEADER_ENTRY, pcToken ) != 0 )
1997 {
1998 SnortSnprintf(ErrorString, ErrStrLen,
1999 "Must end an xff header entry with the '%s' token.",
2000 END_XFF_HEADER_ENTRY);
2001 if( Field_Name )
2002 free(Field_Name);
2003 return( -1 );
2004 }
2005 Parse_State = XFF_STATE_OPEN;
2006 break;
2007 }
2008 default:
2009 {
2010 SnortSnprintf(ErrorString, ErrStrLen,
2011 "xff header parsing error");
2012 if( Field_Name )
2013 free(Field_Name);
2014 return( -1 );
2015 }
2016 }
2017 }
2018 while( Keep_Parsing && ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL) );
2019
2020 if( Field_Name && !addXffFieldName )
2021 {
2022 free(Field_Name);
2023 Field_Name = NULL;
2024 }
2025
2026 if( Parse_State != XFF_STATE_END )
2027 {
2028 SnortSnprintf(ErrorString, ErrStrLen, "xff header parsing error");
2029 return( -1 );
2030 }
2031
2032 /* NOTE: The number of fields added here MUST be represented in HTTP_XFF_BUILTIN_NAMES value
2033 to assure that we reserve room for them on the list. */
2034 if( !Have_XFF )
2035 {
2036 Field_Name = (uint8_t *)SnortStrdup( HTTP_XFF_FIELD_X_FORWARDED_FOR );
2037 if( Add_XFF_Field( ServerConf, Prec_List, Field_Name, 0,
2038 ErrorString, ErrStrLen ) != 0 )
2039 {
2040 SnortSnprintf(ErrorString, ErrStrLen,
2041 "problem adding builtin xff field - too many fields?");
2042 if( Field_Name )
2043 free(Field_Name);
2044 return( -1 );
2045 }
2046 }
2047
2048 if( !Have_TCI )
2049 {
2050 Field_Name = (uint8_t *)SnortStrdup( HTTP_XFF_FIELD_TRUE_CLIENT_IP );
2051 if( Add_XFF_Field( ServerConf, Prec_List, Field_Name, 0,
2052 ErrorString, ErrStrLen ) != 0 )
2053 {
2054 SnortSnprintf(ErrorString, ErrStrLen,
2055 "problem adding builtin xff field - too many fields?");
2056 if( Field_Name )
2057 free(Field_Name);
2058 return( -1 );
2059 }
2060 }
2061
2062
2063 return 0;
2064 }
2065
2066 static char** getHttpXffFields(int* nFields)
2067 {
2068 if (!xffFields[0])
2069 {
2070 if (nFields) *nFields = 0;
2071 return NULL;
2072 }
2073
2074 if (nFields)
2075 {
2076 for ((*nFields) = 0; ((*nFields) < HTTP_MAX_XFF_FIELDS) && xffFields[*nFields];
2077 (*nFields)++)
2078 ;
2079 }
2080 return xffFields;
2081 }
2082
2083 static int ProcessHttpMethodList(HTTPINSPECT_CONF *ServerConf,
2084 char *ErrorString, int ErrStrLen, char **saveptr)
2085 {
2086 HTTP_CMD_CONF *HTTPMethods = NULL;
2087 char *pcToken;
2088 char *cmd;
2089 int iEndCmds = 0;
2090 int iRet;
2091
2092
2093 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2094 if(!pcToken)
2095 {
2096 SnortSnprintf(ErrorString, ErrStrLen,
2097 "Invalid cmd list format.");
2098
2099 return -1;
2100 }
2101
2102 if(strcmp(START_PORT_LIST, pcToken))
2103 {
2104 SnortSnprintf(ErrorString, ErrStrLen,
2105 "Must start a http request method list with the '%s' token.",
2106 START_PORT_LIST);
2107
2108 return -1;
2109 }
2110
2111 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
2112 {
2113 if(!strcmp(END_PORT_LIST, pcToken))
2114 {
2115 iEndCmds = 1;
2116 break;
2117 }
2118
2119 cmd = pcToken;
2120
2121 /* Max method length cannot exceed 256, as this is the size of the key array used in KMapAdd function */
2122 if(strlen(pcToken) > MAX_METHOD_LEN)
2123 {
2124 snprintf(ErrorString, ErrStrLen,
2125 "Length of the http request method should not exceed the max request method length of '%d'.",
2126 MAX_METHOD_LEN);
2127 return -1;
2128 }
2129
2130 HTTPMethods = http_cmd_lookup_find(ServerConf->cmd_lookup, cmd, strlen(cmd), &iRet);
2131
2132 if (HTTPMethods == NULL)
2133 {
2134 /* Add it to the list */
2135 // note that struct includes 1 byte for null, so just add len
2136 HTTPMethods = (HTTP_CMD_CONF *)calloc(1, sizeof(HTTP_CMD_CONF)+strlen(cmd));
2137 if (HTTPMethods == NULL)
2138 {
2139 FatalError("%s(%d) Could not allocate memory for HTTP Method configuration.\n",
2140 __FILE__, __LINE__);
2141 }
2142
2143 strcpy(HTTPMethods->cmd_name, cmd);
2144
2145 http_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), HTTPMethods);
2146 }
2147 }
2148
2149
2150 if(!iEndCmds)
2151 {
2152 snprintf(ErrorString, ErrStrLen,
2153 "Must end '%s' configuration with '%s'.",
2154 HTTP_METHODS, END_PORT_LIST);
2155
2156 return -1;
2157 }
2158
2159 return 0;
2160 }
2161
2162 static int ProcessDecompressionTypeList(HTTPINSPECT_CONF *ServerConf,
2163 char *ConfigType, char *ErrorString, int ErrStrLen, char **saveptr)
2164 {
2165 char *pcToken;
2166 char *cmd;
2167 int iEndCmds = 0;
2168
2169 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2170 if(!pcToken)
2171 {
2172 SnortSnprintf(ErrorString, ErrStrLen,
2173 "Invalid algorithm list format.");
2174
2175 return -1;
2176 }
2177
2178 if(strcmp(START_PORT_LIST, pcToken))
2179 {
2180 SnortSnprintf(ErrorString, ErrStrLen,
2181 "Must start an algotithm list with the '%s' token.",
2182 START_PORT_LIST);
2183
2184 return -1;
2185 }
2186
2187 while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL)
2188 {
2189 if(!strcmp(END_PORT_LIST, pcToken))
2190 {
2191 iEndCmds = 1;
2192 break;
2193 }
2194
2195 cmd = pcToken;
2196
2197 /* FIX THIS: For now, the decompression types are limited to SWF/LZMA, SWF/Deflate, and PDF/Deflate.
2198 Hardcode the comparison logic and storage in the HTTPINSPECT_CONF struc. */
2199 if( 0 == strcmp(ConfigType, INSPECT_SWF))
2200 {
2201 if( 0 == strcmp(cmd, DECOMPRESS_DEFLATE) )
2202 {
2203 ServerConf->file_decomp_modes |= (FILE_SWF_ZLIB_BIT | FILE_REVERT_BIT);
2204 }
2205 #ifdef LZMA
2206 else if( 0 == strcmp(cmd, DECOMPRESS_LZMA) )
2207 {
2208 ServerConf->file_decomp_modes |= (FILE_SWF_LZMA_BIT | FILE_REVERT_BIT);
2209 }
2210 #endif
2211 else
2212 {
2213 snprintf(ErrorString, ErrStrLen,
2214 "Bad cmd element passed to ProcessDecompressionTypeList(): %s", cmd);
2215 return( -1 );
2216
2217 }
2218 }
2219 else if( 0 == strcmp(ConfigType, INSPECT_PDF) )
2220 {
2221 if( 0 == strcmp(cmd, DECOMPRESS_DEFLATE) )
2222 {
2223 ServerConf->file_decomp_modes |= (FILE_PDF_DEFL_BIT | FILE_REVERT_BIT);
2224 }
2225 else
2226 {
2227 snprintf(ErrorString, ErrStrLen,
2228 "Bad cmd passed to ProcessDecompressionTypeList(): %s", cmd);
2229 return( -1 );
2230
2231 }
2232 }
2233 else
2234 {
2235 snprintf(ErrorString, ErrStrLen,
2236 "Bad ConfigType passed to ProcessDecompressionTypeList(): %s", ConfigType);
2237 return( -1 );
2238 }
2239 }
2240
2241 if(!iEndCmds)
2242 {
2243 snprintf(ErrorString, ErrStrLen,
2244 "Must end '%s' configuration with '%s'.",
2245 ConfigType, END_PORT_LIST);
2246
2247 return -1;
2248 }
2249
2250 return 0;
2251 }
2252
2253 /*
2254 ** NAME
2255 ** ProcessMaxSpaces::
2256 */
2257 /**
2258 ** Process and verify the maximum allowed spaces for the
2259 ** server configuration.
2260 **
2261 ** @param ServerConf pointer to the server configuration
2262 ** @param ErrorString error string buffer
2263 ** @param ErrStrLen the length of the error string buffer
2264 ** @param saveptr the strtok_r saved state
2265 **
2266 ** @return an error code integer
2267 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
2268 **
2269 ** @retval 0 successs
2270 ** @retval -1 generic fatal error
2271 ** @retval 1 generic non-fatal error
2272 */
2273 static int ProcessMaxSpaces(HTTPINSPECT_CONF *ServerConf,
2274 char *ErrorString, int ErrStrLen, char **saveptr,
2275 char *configOption, SpaceType type)
2276 {
2277 char *pcToken;
2278 int num_spaces;
2279 char *pcEnd;
2280
2281 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2282 if(pcToken == NULL)
2283 {
2284 SnortSnprintf(ErrorString, ErrStrLen,
2285 "No argument to '%s' token.", configOption);
2286
2287 return -1;
2288 }
2289
2290 num_spaces = SnortStrtolRange(pcToken, &pcEnd, 10, 0 , INT_MAX);
2291 if(*pcEnd)
2292 {
2293 SnortSnprintf(ErrorString, ErrStrLen,
2294 "Invalid argument to '%s'.", configOption);
2295
2296 return -1;
2297 }
2298
2299 if(num_spaces < 0)
2300 {
2301 SnortSnprintf(ErrorString, ErrStrLen,
2302 "Invalid argument to '%s'. Valid range is 0 to 65535.", configOption);
2303
2304 return -1;
2305 }
2306
2307 if(num_spaces > 65535)
2308 {
2309 SnortSnprintf(ErrorString, ErrStrLen,
2310 "Invalid argument to '%s'. Valid range is 0 to 65535.", configOption);
2311
2312 return -1;
2313 }
2314
2315 switch(type)
2316 {
2317 case CONFIG_MAX_SPACES:
2318 ServerConf->max_spaces = num_spaces;
2319 break;
2320 case CONFIG_MAX_JS_WS:
2321 ServerConf->max_js_ws = num_spaces;
2322 break;
2323 default:
2324 break;
2325 }
2326
2327 return 0;
2328 }
2329
2330
2331 /*
2332 ** NAME
2333 ** ProcessServerConf::
2334 */
2335 /**
2336 ** Process the global server configuration.
2337 **
2338 ** Take the configuration and translate into the global server
2339 ** configuration. We also check for any configuration errors and
2340 ** invalid keywords.
2341 **
2342 ** @param ServerConf pointer to the server configuration
2343 ** @param ErrorString error string buffer
2344 ** @param ErrStrLen the length of the error string buffer
2345 ** @param saveptr the strtok_r saved state
2346 **
2347 ** @return an error code integer
2348 ** (0 = success, >0 = non-fatal error, <0 = fatal error)
2349 **
2350 ** @retval 0 successs
2351 ** @retval -1 generic fatal error
2352 ** @retval 1 generic non-fatal error
2353 */
2354 static int ProcessServerConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
2355 HTTPINSPECT_CONF *ServerConf,
2356 char *ErrorString, int ErrStrLen, char **saveptr)
2357 {
2358 char *pcToken;
2359 int iRet;
2360 int iPorts = 0;
2361 HTTPINSPECT_CONF_OPT *ConfOpt;
2362
2363 /*
2364 ** Check for profile keyword first, it's the only place in the
2365 ** configuration that is correct.
2366 */
2367 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2368 if(pcToken == NULL)
2369 {
2370 SnortSnprintf(ErrorString, ErrStrLen,
2371 "WARNING: No tokens to '%s' configuration.", SERVER);
2372
2373 return 1;
2374 }
2375
2376 if(!strcmp(PROFILE_STRING, pcToken))
2377 {
2378 iRet = ProcessProfile(GlobalConf, ServerConf, ErrorString, ErrStrLen, saveptr);
2379 if (iRet)
2380 {
2381 return iRet;
2382 }
2383
2384 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2385 if(pcToken == NULL)
2386 {
2387 SnortSnprintf(ErrorString, ErrStrLen,
2388 "No port list to the profile token.");
2389
2390 return -1;
2391 }
2392
2393 do
2394 {
2395 if(!strcmp(PORTS, pcToken))
2396 {
2397 iRet = ProcessPorts(ServerConf, ErrorString, ErrStrLen, saveptr);
2398 if (iRet)
2399 {
2400 return iRet;
2401 }
2402
2403 iPorts = 1;
2404 }
2405 else if(!strcmp(IIS_UNICODE_MAP, pcToken))
2406 {
2407 iRet = ProcessIISUnicodeMap(&ServerConf->iis_unicode_map,
2408 &ServerConf->iis_unicode_map_filename,
2409 &ServerConf->iis_unicode_codepage,
2410 ErrorString,ErrStrLen, saveptr);
2411 if (iRet)
2412 {
2413 return -1;
2414 }
2415 }
2416 else if(!strcmp(ALLOW_PROXY, pcToken))
2417 {
2418 ServerConf->allow_proxy = 1;
2419 }
2420 else if(!strcmp(FLOW_DEPTH, pcToken) || !strcmp(SERVER_FLOW_DEPTH, pcToken))
2421 {
2422 iRet = ProcessFlowDepth(ServerConf, HI_SI_SERVER_MODE, ErrorString, ErrStrLen, saveptr, pcToken, MAX_SERVER_DEPTH);
2423 if (iRet)
2424 {
2425 return iRet;
2426 }
2427 }
2428 else if(!strcmp(CLIENT_FLOW_DEPTH, pcToken))
2429 {
2430 iRet = ProcessFlowDepth(ServerConf, HI_SI_CLIENT_MODE, ErrorString, ErrStrLen, saveptr, pcToken, MAX_CLIENT_DEPTH);
2431 if (iRet)
2432 {
2433 return iRet;
2434 }
2435 }
2436 else if(!strcmp(POST_DEPTH, pcToken))
2437 {
2438 iRet = ProcessPostDepth(ServerConf, ErrorString, ErrStrLen, saveptr);
2439 if (iRet)
2440 {
2441 return iRet;
2442 }
2443 }
2444 else if(!strcmp(GLOBAL_ALERT, pcToken))
2445 {
2446 ServerConf->no_alerts = 1;
2447 }
2448 else if(!strcmp(OVERSIZE_DIR, pcToken))
2449 {
2450 iRet = ProcessOversizeDir(ServerConf, ErrorString, ErrStrLen, saveptr);
2451 if (iRet)
2452 {
2453 return iRet;
2454 }
2455
2456 }
2457 else if(!strcmp(INSPECT_URI_ONLY, pcToken))
2458 {
2459 ServerConf->uri_only = 1;
2460 }
2461 else if (!strcmp(NORMALIZE_HEADERS, pcToken))
2462 {
2463 ServerConf->normalize_headers = 1;
2464 }
2465 else if (!strcmp(NORMALIZE_COOKIES, pcToken))
2466 {
2467 ServerConf->normalize_cookies = 1;
2468 }
2469 else if (!strcmp(NORMALIZE_UTF, pcToken))
2470 {
2471 ServerConf->normalize_utf = 1;
2472 }
2473 else if (!strcmp(NORMALIZE_JS, pcToken))
2474 {
2475 if(!ServerConf->inspect_response)
2476 {
2477 SnortSnprintf(ErrorString, ErrStrLen,
2478 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, NORMALIZE_JS);
2479 return -1;
2480 }
2481 ServerConf->normalize_javascript = 1;
2482 }
2483 else if(!strcmp(MAX_JS_WS, pcToken))
2484 {
2485 if(!ServerConf->normalize_javascript)
2486 {
2487 SnortSnprintf(ErrorString, ErrStrLen,
2488 "Enable '%s' before setting '%s'", NORMALIZE_JS, MAX_JS_WS);
2489 return -1;
2490 }
2491 iRet = ProcessMaxSpaces(ServerConf, ErrorString, ErrStrLen, saveptr, MAX_JS_WS, CONFIG_MAX_JS_WS);
2492 if (iRet)
2493 {
2494 return iRet;
2495 }
2496 }
2497
2498 else if (!strcmp(INSPECT_COOKIES, pcToken))
2499 {
2500 ServerConf->enable_cookie = 1;
2501 }
2502 else if (!strcmp(INSPECT_RESPONSE, pcToken))
2503 {
2504 ServerConf->inspect_response = 1;
2505 }
2506 else if (!strcmp(HTTP_METHODS, pcToken))
2507 {
2508 iRet = ProcessHttpMethodList(ServerConf, ErrorString, ErrStrLen, saveptr);
2509 if (iRet)
2510 {
2511 return iRet;
2512 }
2513 }
2514 else if (!strcmp(EXTRACT_GZIP, pcToken))
2515 {
2516 if(!ServerConf->inspect_response)
2517 {
2518 SnortSnprintf(ErrorString, ErrStrLen,
2519 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, EXTRACT_GZIP);
2520 return -1;
2521 }
2522
2523 ServerConf->extract_gzip = 1;
2524 }
2525 else if (!strcmp(UNLIMIT_DECOMPRESS, pcToken))
2526 {
2527 if(!ServerConf->extract_gzip)
2528 {
2529 SnortSnprintf(ErrorString, ErrStrLen,
2530 "Enable '%s' before setting '%s'",EXTRACT_GZIP, UNLIMIT_DECOMPRESS);
2531 return -1;
2532 }
2533
2534 if((GlobalConf->compr_depth != MAX_GZIP_DEPTH) && (GlobalConf->decompr_depth != MAX_GZIP_DEPTH))
2535 {
2536 SnortSnprintf(ErrorString, ErrStrLen,
2537 "'%s' and '%s' should be set to max in the default policy to enable '%s'",
2538 COMPRESS_DEPTH, DECOMPRESS_DEPTH, UNLIMIT_DECOMPRESS);
2539 return -1;
2540 }
2541
2542 GlobalConf->compr_depth = GlobalConf->decompr_depth = MAX_GZIP_DEPTH;
2543 ServerConf->unlimited_decompress = 1;
2544 }
2545 #ifdef FILE_DECOMP_SWF
2546 else if (!strcmp(INSPECT_SWF, pcToken))
2547 {
2548 if(!ServerConf->inspect_response)
2549 {
2550 SnortSnprintf(ErrorString, ErrStrLen,
2551 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, INSPECT_SWF);
2552 return -1;
2553 }
2554
2555 ProcessDecompressionTypeList(ServerConf,pcToken,ErrorString,ErrStrLen, saveptr);
2556 }
2557 #endif
2558 #ifdef FILE_DECOMP_PDF
2559 else if (!strcmp(INSPECT_PDF, pcToken))
2560 {
2561 if(!ServerConf->inspect_response)
2562 {
2563 SnortSnprintf(ErrorString, ErrStrLen,
2564 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, INSPECT_PDF);
2565 return -1;
2566 }
2567
2568 ProcessDecompressionTypeList(ServerConf,pcToken,ErrorString,ErrStrLen, saveptr);
2569 }
2570 #endif
2571 else if(!strcmp(MAX_HDR_LENGTH, pcToken))
2572 {
2573 iRet = ProcessMaxHdrLen(ServerConf, ErrorString, ErrStrLen, saveptr);
2574 if (iRet)
2575 {
2576 return iRet;
2577 }
2578 }
2579 else if(!strcmp(MAX_HEADERS, pcToken))
2580 {
2581 iRet = ProcessMaxHeaders(ServerConf, ErrorString, ErrStrLen, saveptr);
2582 if (iRet)
2583 {
2584 return iRet;
2585 }
2586 }
2587 else if(!strcmp(MAX_SPACES, pcToken))
2588 {
2589 iRet = ProcessMaxSpaces(ServerConf, ErrorString, ErrStrLen, saveptr, MAX_SPACES, CONFIG_MAX_SPACES);
2590 if (iRet)
2591 {
2592 return iRet;
2593 }
2594 }
2595 else if(!strcmp(ENABLE_XFF, pcToken))
2596 {
2597 ServerConf->enable_xff = 1;
2598 }
2599 else if(!strcmp(XFF_HEADERS_TOK, pcToken))
2600 {
2601 if(!ServerConf->enable_xff)
2602 {
2603 SnortSnprintf(ErrorString, ErrStrLen,
2604 "Enable '%s' before setting '%s'",ENABLE_XFF, XFF_HEADERS_TOK);
2605 return -1;
2606 }
2607
2608 if( ((iRet = ProcessXFF_HeaderList(ServerConf, ErrorString, ErrStrLen, saveptr)) != 0) )
2609 {
2610 return iRet;
2611 }
2612 }
2613 else if(!strcmp(LOG_URI, pcToken))
2614 {
2615 ServerConf->log_uri = 1;
2616 }
2617 else if(!strcmp(LOG_HOSTNAME, pcToken))
2618 {
2619 ServerConf->log_hostname = 1;
2620 }
2621 else if(!strcmp(SMALL_CHUNK_LENGTH, pcToken))
2622 {
2623 iRet = ProcessSmallChunkLength(ServerConf,ErrorString,ErrStrLen, saveptr);
2624 if (iRet)
2625 {
2626 return iRet;
2627 }
2628 }
2629 else if (!strcmp(LEGACY_MODE, pcToken))
2630 {
2631 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
2632 if (pcToken == NULL)
2633 break;
2634
2635 if(!strcmp(BOOL_YES, pcToken))
2636 {
2637 ServerConf->h2_mode = false;
2638 }
2639 else if(!strcmp(BOOL_NO, pcToken))
2640 {
2641 ServerConf->h2_mode = true;
2642 }
2643 else
2644 {
2645 continue;
2646 }
2647 }
2648 else
2649 {
2650 SnortSnprintf(ErrorString, ErrStrLen,
2651 "Invalid token while configuring the profile token. "
2652 "The only allowed tokens when configuring profiles "
2653 "are: '%s', '%s', '%s', '%s', '%s', '%s', '%s', "
2654 "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', "
2655 #ifdef FILE_DECOMP_SWF
2656 "'%s', "
2657 #endif
2658 #ifdef FILE_DECOMP_PDF
2659 "'%s', "
2660 #endif
2661 "'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', and '%s'. ",
2662 PORTS,IIS_UNICODE_MAP, ALLOW_PROXY, FLOW_DEPTH,
2663 CLIENT_FLOW_DEPTH, GLOBAL_ALERT, OVERSIZE_DIR, MAX_HDR_LENGTH,
2664 INSPECT_URI_ONLY, INSPECT_COOKIES, INSPECT_RESPONSE,
2665 EXTRACT_GZIP,MAX_HEADERS, NORMALIZE_COOKIES, ENABLE_XFF, XFF_HEADERS_TOK,
2666 #ifdef FILE_DECOMP_SWF
2667 INSPECT_SWF,
2668 #endif
2669 #ifdef FILE_DECOMP_PDF
2670 INSPECT_PDF,
2671 #endif
2672 NORMALIZE_HEADERS, NORMALIZE_UTF, UNLIMIT_DECOMPRESS, HTTP_METHODS,
2673 LOG_URI, LOG_HOSTNAME, MAX_SPACES, NORMALIZE_JS, MAX_JS_WS, LEGACY_MODE);
2674
2675 return -1;
2676 }
2677
2678 } while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL);
2679
2680 if(!iPorts)
2681 {
2682 SnortSnprintf(ErrorString, ErrStrLen,
2683 "No port list to the profile token.");
2684
2685 return -1;
2686 }
2687
2688 return 0;
2689 }
2690
2691 /*
2692 ** If there is no profile configuration then we go into the hard-core
2693 ** configuration.
2694 */
2695
2696 hi_ui_config_reset_http_methods(ServerConf);
2697
2698 do
2699 {
2700 if(!strcmp(PORTS, pcToken))
2701 {
2702 iRet = ProcessPorts(ServerConf, ErrorString, ErrStrLen, saveptr);
2703 if (iRet)
2704 {
2705 return iRet;
2706 }
2707 }
2708 else if(!strcmp(FLOW_DEPTH, pcToken) || !strcmp(SERVER_FLOW_DEPTH, pcToken))
2709 {
2710 iRet = ProcessFlowDepth(ServerConf, HI_SI_SERVER_MODE, ErrorString, ErrStrLen, saveptr, pcToken, MAX_SERVER_DEPTH);
2711 if (iRet)
2712 {
2713 return iRet;
2714 }
2715 }
2716 else if(!strcmp(CLIENT_FLOW_DEPTH, pcToken))
2717 {
2718 iRet = ProcessFlowDepth(ServerConf, HI_SI_CLIENT_MODE, ErrorString, ErrStrLen, saveptr, pcToken, MAX_CLIENT_DEPTH);
2719 if (iRet)
2720 {
2721 return iRet;
2722 }
2723 }
2724 else if(!strcmp(POST_DEPTH, pcToken))
2725 {
2726 iRet = ProcessPostDepth(ServerConf, ErrorString, ErrStrLen, saveptr);
2727 if (iRet)
2728 {
2729 return iRet;
2730 }
2731 }
2732 else if(!strcmp(IIS_UNICODE_MAP, pcToken))
2733 {
2734 iRet = ProcessIISUnicodeMap(&ServerConf->iis_unicode_map,
2735 &ServerConf->iis_unicode_map_filename,
2736 &ServerConf->iis_unicode_codepage,
2737 ErrorString, ErrStrLen, saveptr);
2738 if (iRet)
2739 {
2740 return iRet;
2741 }
2742 }
2743 else if(!strcmp(CHUNK_LENGTH, pcToken))
2744 {
2745 iRet = ProcessChunkLength(ServerConf,ErrorString,ErrStrLen, saveptr);
2746 if (iRet)
2747 {
2748 return iRet;
2749 }
2750 }
2751 else if(!strcmp(SMALL_CHUNK_LENGTH, pcToken))
2752 {
2753 iRet = ProcessSmallChunkLength(ServerConf,ErrorString,ErrStrLen, saveptr);
2754 if (iRet)
2755 {
2756 return iRet;
2757 }
2758 }
2759 else if(!strcmp(PIPELINE, pcToken))
2760 {
2761 ServerConf->no_pipeline = 1;
2762 }
2763 else if(!strcmp(NON_STRICT, pcToken))
2764 {
2765 ServerConf->non_strict = 1;
2766 }
2767 else if(!strcmp(ALLOW_PROXY, pcToken))
2768 {
2769 ServerConf->allow_proxy = 1;
2770 }
2771 else if(!strcmp(GLOBAL_ALERT, pcToken))
2772 {
2773 ServerConf->no_alerts = 1;
2774 }
2775 else if(!strcmp(TAB_URI_DELIMITER, pcToken))
2776 {
2777 ServerConf->tab_uri_delimiter = 1;
2778 }
2779 else if(!strcmp(EXTENDED_ASCII, pcToken))
2780 {
2781 ServerConf->extended_ascii_uri = 1;
2782 }
2783 else if (!strcmp(NORMALIZE_HEADERS, pcToken))
2784 {
2785 ServerConf->normalize_headers = 1;
2786 }
2787 else if (!strcmp(NORMALIZE_COOKIES, pcToken))
2788 {
2789 ServerConf->normalize_cookies = 1;
2790 }
2791 else if (!strcmp(NORMALIZE_UTF, pcToken))
2792 {
2793 ServerConf->normalize_utf = 1;
2794 }
2795 else if (!strcmp(NORMALIZE_JS, pcToken))
2796 {
2797 if(!ServerConf->inspect_response)
2798 {
2799 SnortSnprintf(ErrorString, ErrStrLen,
2800 "Enable '%s' before setting '%s'", INSPECT_RESPONSE, NORMALIZE_JS);
2801 return -1;
2802 }
2803 ServerConf->normalize_javascript = 1;
2804 }
2805 else if(!strcmp(MAX_JS_WS, pcToken))
2806 {
2807 if(!ServerConf->normalize_javascript)
2808 {
2809 SnortSnprintf(ErrorString, ErrStrLen,
2810 "Enable '%s' before setting '%s'", NORMALIZE_JS, MAX_JS_WS);
2811 return -1;
2812 }
2813 iRet = ProcessMaxSpaces(ServerConf, ErrorString, ErrStrLen, saveptr, MAX_JS_WS, CONFIG_MAX_JS_WS);
2814 if (iRet)
2815 {
2816 return iRet;
2817 }
2818 }
2819 else if(!strcmp(OVERSIZE_DIR, pcToken))
2820 {
2821 iRet = ProcessOversizeDir(ServerConf, ErrorString, ErrStrLen, saveptr);
2822 if (iRet)
2823 {
2824 return iRet;
2825 }
2826
2827 }
2828 else if(!strcmp(INSPECT_URI_ONLY, pcToken))
2829 {
2830 ServerConf->uri_only = 1;
2831 }
2832
2833 else if(!strcmp(INSPECT_COOKIES, pcToken))
2834 {
2835 ServerConf->enable_cookie = 1;
2836 }
2837 else if(!strcmp(INSPECT_RESPONSE, pcToken))
2838 {
2839 ServerConf->inspect_response = 1;
2840 }
2841 else if (!strcmp(HTTP_METHODS, pcToken))
2842 {
2843 iRet = ProcessHttpMethodList(ServerConf, ErrorString, ErrStrLen, saveptr);
2844 if (iRet)
2845 {
2846 return iRet;
2847 }
2848 }
2849 else if(!strcmp(EXTRACT_GZIP, pcToken))
2850 {
2851 if(!ServerConf->inspect_response)
2852 {
2853 SnortSnprintf(ErrorString, ErrStrLen,
2854 "Enable '%s' inspection before setting '%s'",INSPECT_RESPONSE, EXTRACT_GZIP);
2855 return -1;
2856 }
2857
2858 ServerConf->extract_gzip = 1;
2859 }
2860 else if(!strcmp(UNLIMIT_DECOMPRESS, pcToken))
2861 {
2862 if(!ServerConf->extract_gzip)
2863 {
2864 SnortSnprintf(ErrorString, ErrStrLen,
2865 "Enable '%s' inspection before setting '%s'",EXTRACT_GZIP, UNLIMIT_DECOMPRESS);
2866 return -1;
2867 }
2868 if((GlobalConf->compr_depth != MAX_GZIP_DEPTH) && (GlobalConf->decompr_depth != MAX_GZIP_DEPTH))
2869 {
2870 SnortSnprintf(ErrorString, ErrStrLen,
2871 "'%s' and '%s' should be set to max in the default policy to enable '%s'",
2872 COMPRESS_DEPTH, DECOMPRESS_DEPTH, UNLIMIT_DECOMPRESS);
2873 return -1;
2874 }
2875
2876 GlobalConf->compr_depth = GlobalConf->decompr_depth = MAX_GZIP_DEPTH;
2877 ServerConf->unlimited_decompress = 1;
2878 }
2879 #ifdef FILE_DECOMP_SWF
2880 else if (!strcmp(INSPECT_SWF, pcToken))
2881 {
2882 if(!ServerConf->inspect_response)
2883 {
2884 SnortSnprintf(ErrorString, ErrStrLen,
2885 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, INSPECT_SWF);
2886 return -1;
2887 }
2888
2889 ProcessDecompressionTypeList(ServerConf,pcToken,ErrorString,ErrStrLen, saveptr);
2890 }
2891 #endif
2892 #ifdef FILE_DECOMP_PDF
2893 else if (!strcmp(INSPECT_PDF, pcToken))
2894 {
2895 if(!ServerConf->inspect_response)
2896 {
2897 SnortSnprintf(ErrorString, ErrStrLen,
2898 "Enable '%s' before setting '%s'",INSPECT_RESPONSE, INSPECT_PDF);
2899 return -1;
2900 }
2901
2902 ProcessDecompressionTypeList(ServerConf,pcToken,ErrorString,ErrStrLen, saveptr);
2903 }
2904 #endif
2905 /*
2906 ** Start the CONF_OPT configurations.
2907 */
2908 else if(!strcmp(ASCII, pcToken))
2909 {
2910 ConfOpt = &ServerConf->ascii;
2911 iRet = ProcessConfOpt(ConfOpt, ASCII, ErrorString, ErrStrLen, saveptr);
2912 if (iRet)
2913 {
2914 return iRet;
2915 }
2916 }
2917 else if(!strcmp(UTF_8, pcToken))
2918 {
2919 /*
2920 ** In order for this to work we also need to set ASCII
2921 */
2922 ServerConf->ascii.on = 1;
2923
2924 ConfOpt = &ServerConf->utf_8;
2925 iRet = ProcessConfOpt(ConfOpt, UTF_8, ErrorString, ErrStrLen, saveptr);
2926 if (iRet)
2927 {
2928 return iRet;
2929 }
2930 }
2931 else if(!strcmp(IIS_UNICODE, pcToken))
2932 {
2933 if(ServerConf->iis_unicode_map == NULL)
2934 {
2935 ServerConf->iis_unicode_map = GlobalConf->iis_unicode_map;
2936 }
2937
2938 /*
2939 ** We need to set up:
2940 ** - ASCII
2941 ** - DOUBLE_DECODE
2942 ** - U_ENCODE
2943 ** - BARE_BYTE
2944 ** - IIS_UNICODE
2945 **
2946 ** Base 36 is deprecated and essentially a noop
2947 ** - BASE36
2948 */
2949 ServerConf->ascii.on = 1;
2950
2951 ConfOpt = &ServerConf->iis_unicode;
2952 iRet = ProcessConfOpt(ConfOpt, IIS_UNICODE, ErrorString, ErrStrLen, saveptr);
2953 if (iRet)
2954 {
2955 return iRet;
2956 }
2957 }
2958 else if(!strcmp(DOUBLE_DECODE, pcToken))
2959 {
2960 ServerConf->ascii.on = 1;
2961
2962 ConfOpt = &ServerConf->double_decoding;
2963 iRet = ProcessConfOpt(ConfOpt, DOUBLE_DECODE, ErrorString, ErrStrLen, saveptr);
2964 if (iRet)
2965 {
2966 return iRet;
2967 }
2968 }
2969 else if(!strcmp(U_ENCODE, pcToken))
2970 {
2971 /*
2972 ** We set the unicode map to default if it's not already
2973 ** set.
2974 */
2975 if(ServerConf->iis_unicode_map == NULL)
2976 {
2977 ServerConf->iis_unicode_map = GlobalConf->iis_unicode_map;
2978 }
2979
2980 ConfOpt = &ServerConf->u_encoding;
2981 iRet = ProcessConfOpt(ConfOpt, U_ENCODE, ErrorString, ErrStrLen, saveptr);
2982 if (iRet)
2983 {
2984 return iRet;
2985 }
2986 }
2987 else if(!strcmp(BARE_BYTE, pcToken))
2988 {
2989 ConfOpt = &ServerConf->bare_byte;
2990 iRet = ProcessConfOpt(ConfOpt, BARE_BYTE, ErrorString, ErrStrLen, saveptr);
2991 if (iRet)
2992 {
2993 return iRet;
2994 }
2995 }
2996 else if(!strcmp(BASE36, pcToken))
2997 {
2998 /* Base 36 is deprecated and essentially a noop */
2999 ErrorMessage("WARNING: %s (%d): The \"base36\" option to the "
3000 "\"http_inspect\" preprocessor configuration is "
3001 "deprecated and void of functionality.\n",
3002 file_name, file_line);
3003
3004 /* Need to get and chuck yes/no argument to option since
3005 * we're not doing anything with this anymore. */
3006 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
3007 }
3008 else if(!strcmp(NON_RFC_CHAR, pcToken))
3009 {
3010 iRet = ProcessNonRfcChar(ServerConf, ErrorString, ErrStrLen, saveptr);
3011 if (iRet)
3012 {
3013 return iRet;
3014 }
3015 }
3016 else if(!strcmp(MULTI_SLASH, pcToken))
3017 {
3018 ConfOpt = &ServerConf->multiple_slash;
3019 iRet = ProcessConfOpt(ConfOpt, MULTI_SLASH, ErrorString, ErrStrLen, saveptr);
3020 if (iRet)
3021 {
3022 return iRet;
3023 }
3024 }
3025 else if(!strcmp(IIS_BACKSLASH, pcToken))
3026 {
3027 ConfOpt = &ServerConf->iis_backslash;
3028 iRet = ProcessConfOpt(ConfOpt, IIS_BACKSLASH, ErrorString, ErrStrLen, saveptr);
3029 if (iRet)
3030 {
3031 return iRet;
3032 }
3033 }
3034 else if(!strcmp(DIRECTORY, pcToken))
3035 {
3036 ConfOpt = &ServerConf->directory;
3037 iRet = ProcessConfOpt(ConfOpt, DIRECTORY, ErrorString, ErrStrLen, saveptr);
3038 if (iRet)
3039 {
3040 return iRet;
3041 }
3042 }
3043 else if(!strcmp(APACHE_WS, pcToken))
3044 {
3045 ConfOpt = &ServerConf->apache_whitespace;
3046 iRet = ProcessConfOpt(ConfOpt, APACHE_WS, ErrorString, ErrStrLen, saveptr);
3047 if (iRet)
3048 {
3049 return iRet;
3050 }
3051 }
3052 else if(!strcmp(WHITESPACE, pcToken))
3053 {
3054 iRet = ProcessWhitespaceChars(ServerConf, ErrorString, ErrStrLen, saveptr);
3055 if (iRet)
3056 {
3057 return iRet;
3058 }
3059 }
3060 else if(!strcmp(IIS_DELIMITER, pcToken))
3061 {
3062 ConfOpt = &ServerConf->iis_delimiter;
3063 iRet = ProcessConfOpt(ConfOpt, IIS_DELIMITER, ErrorString, ErrStrLen, saveptr);
3064 if (iRet)
3065 {
3066 return iRet;
3067 }
3068 }
3069 else if(!strcmp(WEBROOT, pcToken))
3070 {
3071 ConfOpt = &ServerConf->webroot;
3072 iRet = ProcessConfOpt(ConfOpt, WEBROOT, ErrorString, ErrStrLen, saveptr);
3073 if (iRet)
3074 {
3075 return iRet;
3076 }
3077 }
3078 else if(!strcmp(MAX_HDR_LENGTH, pcToken))
3079 {
3080 iRet = ProcessMaxHdrLen(ServerConf, ErrorString, ErrStrLen, saveptr);
3081 if (iRet)
3082 {
3083 return iRet;
3084 }
3085 }
3086 else if(!strcmp(MAX_HEADERS, pcToken))
3087 {
3088 iRet = ProcessMaxHeaders(ServerConf, ErrorString, ErrStrLen, saveptr);
3089 if (iRet)
3090 {
3091 return iRet;
3092 }
3093 }
3094 else if(!strcmp(MAX_SPACES, pcToken))
3095 {
3096 iRet = ProcessMaxSpaces(ServerConf, ErrorString, ErrStrLen, saveptr, MAX_SPACES, CONFIG_MAX_SPACES);
3097 if (iRet)
3098 {
3099 return iRet;
3100 }
3101 }
3102 else if(!strcmp(ENABLE_XFF, pcToken))
3103 {
3104 ServerConf->enable_xff = 1;
3105 }
3106 else if(!strcmp(XFF_HEADERS_TOK, pcToken))
3107 {
3108 if(!ServerConf->enable_xff)
3109 {
3110 SnortSnprintf(ErrorString, ErrStrLen,
3111 "Enable '%s' before setting '%s'",ENABLE_XFF, XFF_HEADERS_TOK);
3112 return -1;
3113 }
3114
3115 if( ((iRet = ProcessXFF_HeaderList(ServerConf, ErrorString, ErrStrLen, saveptr)) != 0) )
3116 {
3117 return iRet;
3118 }
3119 }
3120 else if(!strcmp(LOG_URI, pcToken))
3121 {
3122 ServerConf->log_uri = 1;
3123 }
3124 else if(!strcmp(LOG_HOSTNAME, pcToken))
3125 {
3126 ServerConf->log_hostname = 1;
3127 }
3128 else if (!strcmp(LEGACY_MODE, pcToken))
3129 {
3130 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
3131 if(pcToken == NULL)
3132 break;
3133
3134 if(!strcmp(BOOL_YES, pcToken))
3135 {
3136 ServerConf->h2_mode = false;
3137 }
3138 else if(!strcmp(BOOL_NO, pcToken))
3139 {
3140 ServerConf->h2_mode = true;
3141 }
3142 else
3143 {
3144 continue;
3145 }
3146 }
3147 else
3148 {
3149 SnortSnprintf(ErrorString, ErrStrLen,
3150 "Invalid keyword '%s' for server configuration.",
3151 pcToken);
3152
3153 return -1;
3154 }
3155
3156 } while ((pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr)) != NULL);
3157
3158 return 0;
3159 }
3160
3161 static void PrintFileDecompOpt(HTTPINSPECT_CONF *ServerConf)
3162 {
3163 LogMessage(" Decompress response files: %s %s %s\n",
3164 ((ServerConf->file_decomp_modes & FILE_SWF_ZLIB_BIT) != 0) ? "SWF-ZLIB" : "",
3165 ((ServerConf->file_decomp_modes & FILE_SWF_LZMA_BIT) != 0) ? "SWF-LZMA" : "",
3166 ((ServerConf->file_decomp_modes & FILE_PDF_DEFL_BIT) != 0) ? "PDF-DEFL" : "");
3167 }
3168
3169 static int PrintConfOpt(HTTPINSPECT_CONF_OPT *ConfOpt, char *Option)
3170 {
3171 if(!ConfOpt || !Option)
3172 {
3173 return HI_INVALID_ARG;
3174 }
3175
3176 if(ConfOpt->on)
3177 {
3178 LogMessage(" %s: YES alert: %s\n", Option,
3179 ConfOpt->alert ? "YES" : "NO");
3180 }
3181 else
3182 {
3183 LogMessage(" %s: OFF\n", Option);
3184 }
3185
3186 return 0;
3187 }
3188
3189 static int PrintServerConf(HTTPINSPECT_CONF *ServerConf)
3190 {
3191 char buf[STD_BUF+1];
3192 int iCtr;
3193 int iChar = 0;
3194 char* paf = "";
3195 PROFILES prof;
3196
3197 if(!ServerConf)
3198 {
3199 return HI_INVALID_ARG;
3200 }
3201
3202 prof = ServerConf->profile;
3203 LogMessage(" Server profile: %s\n",
3204 prof==HI_ALL?"All":
3205 prof==HI_APACHE?"Apache":
3206 prof==HI_IIS?"IIS":
3207 prof==HI_IIS4?"IIS4":"IIS5");
3208
3209
3210 memset(buf, 0, STD_BUF+1);
3211
3212 if ( ScPafEnabled() && stream_api )
3213 paf = " (PAF)";
3214
3215 SnortSnprintf(buf, STD_BUF + 1, " Ports%s: ", paf);
3216
3217 /*
3218 ** Print out all the applicable ports.
3219 */
3220 for(iCtr = 0; iCtr < MAXPORTS; iCtr++)
3221 {
3222 if( isPortEnabled( ServerConf->ports, iCtr ) )
3223 {
3224 sfsnprintfappend(buf, STD_BUF, "%d ", iCtr);
3225 }
3226 }
3227
3228 LogMessage("%s\n", buf);
3229
3230 LogMessage(" Server Flow Depth: %d\n", ServerConf->server_flow_depth);
3231 LogMessage(" Client Flow Depth: %d\n", ServerConf->client_flow_depth);
3232 LogMessage(" Max Chunk Length: %d\n", ServerConf->chunk_length);
3233 if (ServerConf->small_chunk_length.size > 0)
3234 LogMessage(" Small Chunk Length Evasion: chunk size <= %u, threshold >= %u times\n",
3235 ServerConf->small_chunk_length.size, ServerConf->small_chunk_length.num);
3236 LogMessage(" Max Header Field Length: %d\n", ServerConf->max_hdr_len);
3237 LogMessage(" Max Number Header Fields: %d\n", ServerConf->max_headers);
3238 LogMessage(" Max Number of WhiteSpaces allowed with header folding: %d\n", ServerConf->max_spaces);
3239 LogMessage(" Inspect Pipeline Requests: %s\n",
3240 ServerConf->no_pipeline ? "NO" : "YES");
3241 LogMessage(" URI Discovery Strict Mode: %s\n",
3242 ServerConf->non_strict ? "NO" : "YES");
3243 LogMessage(" Allow Proxy Usage: %s\n",
3244 ServerConf->allow_proxy ? "YES" : "NO");
3245 LogMessage(" Disable Alerting: %s\n",
3246 ServerConf->no_alerts ? "YES":"NO");
3247 LogMessage(" Oversize Dir Length: %d\n",
3248 ServerConf->long_dir);
3249 LogMessage(" Only inspect URI: %s\n",
3250 ServerConf->uri_only ? "YES" : "NO");
3251 LogMessage(" Normalize HTTP Headers: %s\n",
3252 ServerConf->normalize_headers ? "YES" : "NO");
3253 LogMessage(" Inspect HTTP Cookies: %s\n",
3254 ServerConf->enable_cookie ? "YES" : "NO");
3255 LogMessage(" Inspect HTTP Responses: %s\n",
3256 ServerConf->inspect_response ? "YES" : "NO");
3257 LogMessage(" Extract Gzip from responses: %s\n",
3258 ServerConf->extract_gzip ? "YES" : "NO");
3259 PrintFileDecompOpt(ServerConf);
3260 LogMessage(" Unlimited decompression of gzip data from responses: %s\n",
3261 ServerConf->unlimited_decompress ? "YES" : "NO");
3262 LogMessage(" Normalize Javascripts in HTTP Responses: %s\n",
3263 ServerConf->normalize_javascript ? "YES" : "NO");
3264 if(ServerConf->normalize_javascript)
3265 {
3266 if(ServerConf->max_js_ws)
3267 LogMessage(" Max Number of WhiteSpaces allowed with Javascript Obfuscation in HTTP responses: %d\n", ServerConf->max_js_ws);
3268 }
3269 LogMessage(" Normalize HTTP Cookies: %s\n",
3270 ServerConf->normalize_cookies ? "YES" : "NO");
3271 LogMessage(" Enable XFF and True Client IP: %s\n",
3272 ServerConf->enable_xff ? "YES" : "NO");
3273 LogMessage(" Log HTTP URI data: %s\n",
3274 ServerConf->log_uri ? "YES" : "NO");
3275 LogMessage(" Log HTTP Hostname data: %s\n",
3276 ServerConf->log_hostname ? "YES" : "NO");
3277 LogMessage(" Extended ASCII code support in URI: %s\n",
3278 ServerConf->extended_ascii_uri ? "YES" : "NO");
3279
3280
3281 PrintConfOpt(&ServerConf->ascii, "Ascii");
3282 PrintConfOpt(&ServerConf->double_decoding, "Double Decoding");
3283 PrintConfOpt(&ServerConf->u_encoding, "%U Encoding");
3284 PrintConfOpt(&ServerConf->bare_byte, "Bare Byte");
3285 PrintConfOpt(&ServerConf->utf_8, "UTF 8");
3286 PrintConfOpt(&ServerConf->iis_unicode, "IIS Unicode");
3287 PrintConfOpt(&ServerConf->multiple_slash, "Multiple Slash");
3288 PrintConfOpt(&ServerConf->iis_backslash, "IIS Backslash");
3289 PrintConfOpt(&ServerConf->directory, "Directory Traversal");
3290 PrintConfOpt(&ServerConf->webroot, "Web Root Traversal");
3291 PrintConfOpt(&ServerConf->apache_whitespace, "Apache WhiteSpace");
3292 PrintConfOpt(&ServerConf->iis_delimiter, "IIS Delimiter");
3293
3294 if(ServerConf->iis_unicode_map_filename)
3295 {
3296 LogMessage(" IIS Unicode Map Filename: %s\n",
3297 ServerConf->iis_unicode_map_filename);
3298 LogMessage(" IIS Unicode Map Codepage: %d\n",
3299 ServerConf->iis_unicode_codepage);
3300 }
3301 else if(ServerConf->iis_unicode_map)
3302 {
3303 LogMessage(" IIS Unicode Map: "
3304 "GLOBAL IIS UNICODE MAP CONFIG\n");
3305 }
3306 else
3307 {
3308 LogMessage(" IIS Unicode Map: NOT CONFIGURED\n");
3309 }
3310
3311 /*
3312 ** Print out the non-rfc chars
3313 */
3314 memset(buf, 0, STD_BUF+1);
3315 SnortSnprintf(buf, STD_BUF + 1, " Non-RFC Compliant Characters: ");
3316 for(iCtr = 0; iCtr < 256; iCtr++)
3317 {
3318 if(ServerConf->non_rfc_chars[iCtr])
3319 {
3320 sfsnprintfappend(buf, STD_BUF, "0x%.2x ", (u_char)iCtr);
3321 iChar = 1;
3322 }
3323 }
3324
3325 if(!iChar)
3326 {
3327 sfsnprintfappend(buf, STD_BUF, "NONE");
3328 }
3329
3330 LogMessage("%s\n", buf);
3331
3332 /*
3333 ** Print out the whitespace chars
3334 */
3335 iChar = 0;
3336 memset(buf, 0, STD_BUF+1);
3337 SnortSnprintf(buf, STD_BUF + 1, " Whitespace Characters: ");
3338 for(iCtr = 0; iCtr < 256; iCtr++)
3339 {
3340 if(ServerConf->whitespace[iCtr])
3341 {
3342 sfsnprintfappend(buf, STD_BUF, "0x%.2x ", (u_char)iCtr);
3343 iChar = 1;
3344 }
3345 }
3346
3347 if(!iChar)
3348 {
3349 sfsnprintfappend(buf, STD_BUF, "NONE");
3350 }
3351
3352 LogMessage("%s\n", buf);
3353
3354 LogMessage(" Legacy mode: %s\n",
3355 ServerConf->h2_mode ? "YES" : "NO");
3356
3357 return 0;
3358 }
3359
3360 static void registerPortsWithStream( HTTPINSPECT_CONF *policy, char *network )
3361 {
3362 uint32_t port;
3363 uint32_t dir = 0;
3364
3365 if( policy->client_flow_depth > -1 )
3366 dir |= SSN_DIR_FROM_CLIENT;
3367 if( ( policy->server_extract_size > -1 ) )
3368 dir |= SSN_DIR_FROM_SERVER;
3369
3370 for ( port = 0; port < MAXPORTS; port++ )
3371 {
3372 if( isPortEnabled( policy->ports, port ) )
3373 stream_api->register_reassembly_port( network, port, dir );
3374 }
3375 }
3376
3377 static void enableHiForConfiguredPorts( struct _SnortConfig *sc, HTTPINSPECT_CONF *policy )
3378 {
3379 int port;
3380
3381 for ( port = 0; port < MAXPORTS; port++ )
3382 {
3383 if( isPortEnabled( policy->ports, port ) )
3384 session_api->enable_preproc_for_port( sc, PP_HTTPINSPECT, PROTO_BIT__TCP, port );
3385 }
3386 }
3387
3388 int ProcessUniqueServerConf(struct _SnortConfig *sc, HTTPINSPECT_GLOBAL_CONF *GlobalConf,
3389 char *ErrorString, int ErrStrLen, char **saveptr)
3390 {
3391 char *pcToken;
3392 char *pIpAddressList = NULL;
3393 char *pIpAddressList2 = NULL;
3394 char *brkt = NULL;
3395 char firstIpAddress = 1;
3396 sfcidr_t Ip;
3397 HTTPINSPECT_CONF *ServerConf = NULL;
3398 int iRet;
3399 int retVal = -1;
3400
3401 pcToken = strtok_r(NULL, CONF_SEPARATORS, saveptr);
3402 if(!pcToken)
3403 {
3404 SnortSnprintf(ErrorString, ErrStrLen,
3405 "No arguments to '%s' token.", SERVER);
3406
3407 retVal = -1;
3408 goto _return;
3409 }
3410
3411 /*
3412 ** Check for the default configuration first
3413 */
3414 if (strcasecmp(SERVER_DEFAULT, pcToken) == 0)
3415 {
3416 if (GlobalConf->global_server != NULL)
3417 {
3418 SnortSnprintf(ErrorString, ErrStrLen,
3419 "Cannot configure '%s' settings more than once.",
3420 GLOBAL_SERVER);
3421
3422 goto _return;
3423 }
3424
3425 GlobalConf->global_server =
3426 (HTTPINSPECT_CONF *)SnortAlloc(sizeof(HTTPINSPECT_CONF));
3427
3428 ServerConf = GlobalConf->global_server;
3429
3430 iRet = hi_ui_config_default(ServerConf);
3431 if (iRet)
3432 {
3433 snprintf(ErrorString, ErrStrLen,
3434 "Error configuring default global configuration.");
3435 return -1;
3436 }
3437
3438 iRet = ProcessServerConf(GlobalConf, ServerConf, ErrorString, ErrStrLen, saveptr);
3439 if (iRet)
3440 {
3441 retVal = iRet;
3442 goto _return;
3443 }
3444
3445 // register enabled ports for reassembly with Stream for the default
3446 registerPortsWithStream( ServerConf, NULL );
3447 enableHiForConfiguredPorts( sc, ServerConf );
3448
3449 /*
3450 ** Start writing out the Default Server Config
3451 */
3452 LogMessage(" DEFAULT SERVER CONFIG:\n");
3453 }
3454 else
3455 {
3456 /*
3457 ** Convert string to IP address
3458 */
3459 /* get the first delimiter*/
3460 if(strcmp(START_IPADDR_LIST, pcToken) == 0)
3461 {
3462 /*list begin token matched*/
3463 if ((pIpAddressList = strtok_r(NULL, END_IPADDR_LIST, saveptr)) == NULL)
3464 {
3465 SnortSnprintf(ErrorString, ErrStrLen,
3466 "Invalid IP Address list in '%s' token.", SERVER);
3467
3468 goto _return;
3469 }
3470 }
3471 else
3472 {
3473 /*list begin didn't match so this must be an IP address*/
3474 pIpAddressList = pcToken;
3475 }
3476
3477
3478 pIpAddressList2 = strdup(pIpAddressList);
3479 if (!pIpAddressList2)
3480 {
3481 SnortSnprintf(ErrorString, ErrStrLen,
3482 "Could not allocate memory for server configuration.");
3483
3484 goto _return;
3485 }
3486
3487
3488
3489 for (pcToken = strtok_r(pIpAddressList, CONF_SEPARATORS, &brkt);
3490 pcToken;
3491 pcToken = strtok_r(NULL, CONF_SEPARATORS, &brkt))
3492 {
3493
3494 if (sfip_pton(pcToken, &Ip) != SFIP_SUCCESS)
3495 {
3496 SnortSnprintf(ErrorString, ErrStrLen,
3497 "Invalid IP to '%s' token.", SERVER);
3498
3499 goto _return;
3500 }
3501
3502 /*
3503 ** allocate the memory for the server configuration
3504 */
3505 if (firstIpAddress)
3506 {
3507 ServerConf = (HTTPINSPECT_CONF *)calloc(1, sizeof(HTTPINSPECT_CONF));
3508 if(!ServerConf)
3509 {
3510 SnortSnprintf(ErrorString, ErrStrLen,
3511 "Could not allocate memory for server configuration.");
3512
3513 goto _return;
3514 }
3515
3516 iRet = ProcessServerConf(GlobalConf, ServerConf, ErrorString, ErrStrLen, saveptr);
3517 if (iRet)
3518 {
3519 retVal = iRet;
3520 goto _return;
3521 }
3522 }
3523
3524 iRet = hi_ui_config_add_server(GlobalConf, &Ip, ServerConf);
3525 if (iRet)
3526 {
3527 /*
3528 ** Check for already added servers
3529 */
3530 if(iRet == HI_NONFATAL_ERR)
3531 {
3532 SnortSnprintf(ErrorString, ErrStrLen,
3533 "Duplicate server configuration.");
3534
3535 goto _return;
3536 }
3537 else
3538 {
3539 SnortSnprintf(ErrorString, ErrStrLen,
3540 "Error when adding server configuration.");
3541
3542 goto _return;
3543 }
3544 }
3545
3546 // register enabled ports for reassembly with Stream for the current netowrk
3547 registerPortsWithStream( ServerConf, pcToken );
3548 enableHiForConfiguredPorts( sc, ServerConf );
3549
3550 if (firstIpAddress)
3551 {
3552 //process the first IP address as usual
3553 firstIpAddress = 0;
3554 }
3555
3556 //create a reference
3557 ServerConf->referenceCount++;
3558
3559 }
3560
3561 if (firstIpAddress)
3562 {
3563 //no IP address was found
3564 SnortSnprintf(ErrorString, ErrStrLen,
3565 "Invalid IP Address list in '%s' token.", SERVER);
3566
3567 goto _return;
3568 }
3569
3570 /*
3571 ** Print out the configuration header
3572 */
3573 LogMessage(" SERVER: %s\n", pIpAddressList2);
3574 }
3575
3576 /*
3577 ** Finish printing out the server configuration
3578 */
3579 PrintServerConf(ServerConf);
3580
3581 retVal = 0;
3582
3583 _return:
3584 if (pIpAddressList2)
3585 {
3586 free(pIpAddressList2);
3587 }
3588 return retVal;
3589 }
3590
3591 int PrintGlobalConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf)
3592 {
3593 LogMessage("HttpInspect Config:\n");
3594
3595 LogMessage(" GLOBAL CONFIG\n");
3596 if(GlobalConf->disabled)
3597 {
3598 LogMessage(" Http Inspect: INACTIVE\n");
3599 LogMessage(" Max Gzip Memory: %d\n",
3600 GlobalConf->max_gzip_mem);
3601 LogMessage(" Memcap used for logging URI and Hostname: %u\n",
3602 GlobalConf->memcap);
3603 return 0;
3604 }
3605 LogMessage(" Detect Proxy Usage: %s\n",
3606 GlobalConf->proxy_alert ? "YES" : "NO");
3607 LogMessage(" IIS Unicode Map Filename: %s\n",
3608 GlobalConf->iis_unicode_map_filename);
3609 LogMessage(" IIS Unicode Map Codepage: %d\n",
3610 GlobalConf->iis_unicode_codepage);
3611 LogMessage(" Memcap used for logging URI and Hostname: %u\n",
3612 GlobalConf->memcap);
3613 LogMessage(" Max Gzip Memory: %d\n",
3614 GlobalConf->max_gzip_mem);
3615 LogMessage(" Max Gzip Sessions: %d\n",
3616 GlobalConf->max_gzip_sessions);
3617 LogMessage(" Gzip Compress Depth: %d\n",
3618 GlobalConf->compr_depth);
3619 LogMessage(" Gzip Decompress Depth: %d\n",
3620 GlobalConf->decompr_depth);
3621 LogMessage(" Normalize Random Nulls in Text: %s\n",
3622 GlobalConf->normalize_nulls ? "YES" : "NO");
3623
3624 return 0;
3625 }
3626
3627 /*
3628 ** NAME
3629 ** LogEvents::
3630 */
3631 /**
3632 ** This is the routine that logs HttpInspect alerts through Snort.
3633 **
3634 ** Every Session gets looked at for any logged events, and if there are
3635 ** events to be logged then we select the one with the highest priority.
3636 **
3637 ** We use a generic event structure that we set for each different event
3638 ** structure. This way we can use the same code for event logging regardless
3639 ** of what type of event strucure we are dealing with.
3640 **
3641 ** The important things to know about this function is how to work with
3642 ** the event queue. The number of unique events is contained in the
3643 ** stack_count variable. So we loop through all the unique events and
3644 ** find which one has the highest priority. During this loop, we also
3645 ** re-initialize the individual event counts for the next iteration, saving
3646 ** us time in a separate initialization phase.
3647 **
3648 ** After we've iterated through all the events and found the one with the
3649 ** highest priority, we then log that event through snort.
3650 **
3651 ** We've mapped the HttpInspect and the Snort alert IDs together, so we
3652 ** can access them directly instead of having a more complex mapping
3653 ** function. It's the only good way to do this.
3654 **
3655 ** @param Session pointer to Session construct
3656 ** @param p pointer to the Snort packet construct
3657 ** @param iInspectMode inspection mode to take event queue from
3658 **
3659 ** @return integer
3660 **
3661 ** @retval 0 this function only return success
3662 */
3663 static inline int LogEvents(HI_SESSION *hi_ssn, Packet *p,
3664 int iInspectMode, HttpSessionData *hsd)
3665 {
3666 HI_GEN_EVENTS GenEvents;
3667 HI_EVENT *OrigEvent;
3668 HI_EVENT *HiEvent = NULL;
3669 uint64_t uiMask = 0;
3670 int iGenerator;
3671 int iStackCnt;
3672 uint64_t iEvent;
3673 int iCtr;
3674
3675 /*
3676 ** Set the session ptr, if applicable
3677 */
3678 if(iInspectMode == HI_SI_CLIENT_MODE)
3679 {
3680 GenEvents.stack = hi_ssn->client.event_list.stack;
3681 GenEvents.stack_count = &(hi_ssn->client.event_list.stack_count);
3682 GenEvents.events = hi_ssn->client.event_list.events;
3683
3684 iGenerator = GENERATOR_SPP_HTTP_INSPECT_CLIENT;
3685 }
3686 else if(iInspectMode == HI_SI_SERVER_MODE)
3687 {
3688 GenEvents.stack = hi_ssn->server.event_list.stack;
3689 GenEvents.stack_count = &(hi_ssn->server.event_list.stack_count);
3690 GenEvents.events = hi_ssn->server.event_list.events;
3691
3692 iGenerator = GENERATOR_SPP_HTTP_INSPECT;
3693 }
3694 else
3695 {
3696 GenEvents.stack = hi_ssn->anom_server.event_list.stack;
3697 GenEvents.stack_count = &(hi_ssn->anom_server.event_list.stack_count);
3698 GenEvents.events = hi_ssn->anom_server.event_list.events;
3699
3700 iGenerator = GENERATOR_SPP_HTTP_INSPECT;
3701 }
3702
3703 /*
3704 ** Now starts the generic event processing
3705 */
3706 iStackCnt = *(GenEvents.stack_count);
3707
3708 /*
3709 ** IMPORTANT::
3710 ** We have to check the stack count of the event queue before we process
3711 ** an log.
3712 */
3713 if(iStackCnt == 0)
3714 {
3715 return 0;
3716 }
3717
3718 /*
3719 ** Cycle through the events and select the event with the highest
3720 ** priority.
3721 */
3722 for(iCtr = 0; iCtr < iStackCnt; iCtr++)
3723 {
3724 iEvent = (uint64_t)GenEvents.stack[iCtr];
3725 OrigEvent = &(GenEvents.events[iEvent]);
3726
3727 /*
3728 ** Set the event to start off the comparison
3729 */
3730 if(!HiEvent)
3731 {
3732 HiEvent = OrigEvent;
3733 }
3734
3735 /*
3736 ** This is our "comparison function". Log the event with the highest
3737 ** priority.
3738 */
3739 if(OrigEvent->event_info->priority < HiEvent->event_info->priority)
3740 {
3741 HiEvent = OrigEvent;
3742 }
3743
3744 /*
3745 ** IMPORTANT:
3746 ** This is how we reset the events in the event queue.
3747 ** If you miss this step, you can be really screwed.
3748 */
3749 OrigEvent->count = 0;
3750 }
3751
3752 /*
3753 ** We use the iEvent+1 because the event IDs between snort and
3754 ** HttpInspect are mapped off-by-one. Don't ask why, drink Bud
3755 ** Dry . . . They're mapped off-by one because in the internal
3756 ** HttpInspect queue, events are mapped starting at 0. For some
3757 ** reason, it appears that the first event can't be zero, so we
3758 ** use the internal value and add one for snort.
3759 */
3760 iEvent = (uint64_t)HiEvent->event_info->alert_id + 1;
3761
3762 uiMask = (uint64_t)1 << (iEvent & 63);
3763
3764 if (hsd != NULL)
3765 {
3766 /* We've already logged this event for this session,
3767 * don't log it again */
3768 if (hsd->event_flags & uiMask)
3769 return 0;
3770 hsd->event_flags |= uiMask;
3771 }
3772
3773 SnortEventqAdd(iGenerator, iEvent, 1, 0, 3, HiEvent->event_info->alert_str,0);
3774
3775 /*
3776 ** Reset the event queue stack counter, in the case of pipelined
3777 ** requests.
3778 */
3779 *(GenEvents.stack_count) = 0;
3780
3781 return 0;
3782 }
3783
3784 static inline int SetSiInput(HI_SI_INPUT *SiInput, Packet *p)
3785 {
3786 IP_COPY_VALUE(SiInput->sip, GET_SRC_IP(p));
3787 IP_COPY_VALUE(SiInput->dip, GET_DST_IP(p));
3788 SiInput->sport = p->sp;
3789 SiInput->dport = p->dp;
3790
3791 /*
3792 ** We now set the packet direction
3793 */
3794 if(p->ssnptr &&
3795 session_api->get_session_flags(p->ssnptr) & SSNFLAG_MIDSTREAM)
3796 {
3797 SiInput->pdir = HI_SI_NO_MODE;
3798 }
3799 else if(p->packet_flags & PKT_FROM_SERVER)
3800 {
3801 SiInput->pdir = HI_SI_SERVER_MODE;
3802 }
3803 else if(p->packet_flags & PKT_FROM_CLIENT)
3804 {
3805 SiInput->pdir = HI_SI_CLIENT_MODE;
3806 }
3807 else
3808 {
3809 SiInput->pdir = HI_SI_NO_MODE;
3810 }
3811
3812 return HI_SUCCESS;
3813
3814 }
3815
3816 static inline void ApplyClientFlowDepth (Packet* p, int flow_depth)
3817 {
3818 switch (flow_depth)
3819 {
3820 case -1:
3821 // Inspect none of the client if there is normalized/extracted
3822 // URI/Method/Header/Body data */
3823 SetDetectLimit(p, 0);
3824 break;
3825
3826 case 0:
3827 // Inspect all of the client, even if there is normalized/extracted
3828 // URI/Method/Header/Body data */
3829 /* XXX: HUGE performance hit here */
3830 SetDetectLimit(p, p->dsize);
3831 break;
3832
3833 default:
3834 // Limit inspection of the client, even if there is normalized/extracted
3835 // URI/Method/Header/Body data */
3836 /* XXX: Potential performance hit here */
3837 if (flow_depth < p->dsize)
3838 {
3839 SetDetectLimit(p, flow_depth);
3840 }
3841 else
3842 {
3843 SetDetectLimit(p, p->dsize);
3844 }
3845 break;
3846 }
3847 }
3848
3849 // FIXTHIS extra data masks should only be updated as extra data changes state
3850 // eg just once when captured; this function is called on every packet and
3851 // repeatedly sets the flags on session
3852 static inline void HttpLogFuncs(HTTPINSPECT_GLOBAL_CONF *GlobalConf, HttpSessionData *hsd, Packet *p, int iCallDetect )
3853 {
3854 if(!hsd)
3855 return;
3856
3857 /* for pipelined HTTP requests */
3858 if ( !iCallDetect )
3859 stream_api->clear_extra_data(p->ssnptr, p, 0);
3860
3861 if ( hsd->tList_start != NULL )
3862 {
3863 if( hsd->tList_start->tID == hsd->http_resp_id || hsd->tList_end->tID == hsd->http_req_id )
3864 {
3865 if(!(p->packet_flags & PKT_STREAM_INSERT) && !(p->packet_flags & PKT_REBUILT_STREAM))
3866 SetExtraData(p, GlobalConf->xtra_trueip_id);
3867 else
3868 stream_api->set_extra_data(p->ssnptr, p, GlobalConf->xtra_trueip_id);
3869 }
3870 }
3871
3872 if(hsd->log_flags & HTTP_LOG_URI)
3873 {
3874 stream_api->set_extra_data(p->ssnptr, p, GlobalConf->xtra_uri_id);
3875 }
3876
3877 if(hsd->log_flags & HTTP_LOG_HOSTNAME)
3878 {
3879 stream_api->set_extra_data(p->ssnptr, p, GlobalConf->xtra_hname_id);
3880 }
3881
3882 #ifndef SOURCEFIRE
3883 if(hsd->log_flags & HTTP_LOG_JSNORM_DATA)
3884 {
3885 SetExtraData(p, GlobalConf->xtra_jsnorm_id);
3886 }
3887 if(hsd->log_flags & HTTP_LOG_GZIP_DATA)
3888 {
3889 SetExtraData(p, GlobalConf->xtra_gzip_id);
3890 }
3891 #endif
3892 }
3893
3894 static inline void setFileName(Packet *p)
3895 {
3896 uint8_t *buf = NULL;
3897 uint32_t len = 0;
3898 uint32_t type = 0;
3899 GetHttpUriData(p->ssnptr, &buf, &len, &type);
3900 file_api->set_file_name (p->ssnptr, buf, len, false);
3901 }
3902
3903
3904 static inline bool rfc_2616_token(u_char c)
3905 {
3906 return isalpha(c) || isdigit(c) ||
3907 c == '!' || c == '#' || c == '$' || c == '%' ||
3908 c == '&' || c == '\'' || c == '*' || c == '+' ||
3909 c == '-' || c == '.' || c == '^' || c == '_' ||
3910 c == '`' || c == '|' || c == '~';
3911 }
3912
3913 static inline bool rfc5987_attr_char(u_char c)
3914 {
3915 return rfc_2616_token(c) && (( c != '*')|| (c !='\'') || (c !='%'));
3916 }
3917
3918
3919 /* Extract the filename from the content-dispostion header- RFC6266 */
3920 static inline int extract_file_name(u_char *start, int length, u_char **fname_ptr, uint8_t *charset)
3921 {
3922 u_char *cur = start, *tmp = NULL;
3923 u_char *end = start+length;
3924 u_char *fname_begin = NULL;
3925 u_char *fname_end = NULL;
3926 bool char_set = false;
3927 enum {
3928 CD_STATE_START,
3929 CD_STATE_BEFORE_VAL,
3930 CD_STATE_VAL,
3931 CD_STATE_QUOTED_VAL,
3932 CD_STATE_BEFORE_EXT_VAL,
3933 CD_STATE_CHARSET,
3934 CD_STATE_LANGUAGE,
3935 CD_STATE_EXT_VAL,
3936 CD_STATE_FINAL
3937 };
3938 const char *cd_file1 = "filename";
3939 const char *cd_file2 = "filename*";
3940
3941 if (length <= 0)
3942 return -1;
3943 uint8_t state = CD_STATE_START;
3944
3945 while(cur < end)
3946 {
3947 switch(state)
3948 {
3949 case CD_STATE_START:
3950 {
3951 if( (tmp = (u_char *)SnortStrcasestr((const char *)cur, end-cur, cd_file2)))
3952 {
3953 state = CD_STATE_BEFORE_EXT_VAL;
3954 cur = tmp + strlen(cd_file2)-1;
3955 }
3956 else if( (tmp = (u_char *)SnortStrcasestr((const char *)cur, end-cur, cd_file1)))
3957 {
3958 state = CD_STATE_BEFORE_VAL;
3959 cur = tmp + strlen(cd_file1)-1;
3960 }
3961 else
3962 return -1;
3963 }
3964 break;
3965 case CD_STATE_BEFORE_VAL:
3966 {
3967 if(*cur == '=')
3968 state = CD_STATE_VAL;
3969 else if( *cur != ' ')
3970 state = CD_STATE_START;
3971 }
3972 break;
3973 case CD_STATE_VAL:
3974 {
3975 if( !fname_begin && *cur == '"')
3976 state = CD_STATE_QUOTED_VAL;
3977 else if(rfc_2616_token(*cur))
3978 {
3979 if(!fname_begin)
3980 fname_begin = cur;
3981 }
3982 else if(*cur == ';' || *cur == '\r' || *cur == '\n' || *cur == ' ' || *cur == '\t')
3983 {
3984 if(fname_begin)
3985 {
3986 fname_end = cur - 1;
3987 state = CD_STATE_FINAL;
3988 }
3989 }
3990 else
3991 return -1;
3992 }
3993 break;
3994 case CD_STATE_QUOTED_VAL:
3995 {
3996 if(!fname_begin)
3997 fname_begin = cur;
3998 if(*cur == '"' )
3999 {
4000 fname_end = cur;
4001 state = CD_STATE_FINAL;
4002 }
4003 }
4004 break;
4005
4006 case CD_STATE_BEFORE_EXT_VAL:
4007 {
4008 if(*cur == '=')
4009 state = CD_STATE_CHARSET;
4010 else if( *cur != ' ')
4011 state = CD_STATE_START;
4012 }
4013 break;
4014 case CD_STATE_CHARSET:
4015 {
4016 if( *cur == '\'')
4017 {
4018 if(!char_set)
4019 return -1;
4020 else
4021 state = CD_STATE_LANGUAGE;
4022 }
4023 else if(!char_set)
4024 {
4025 /* Ignore space before the ext-value */
4026 while(cur < end && *cur == ' ' )
4027 cur++;
4028 if(cur < end)
4029 {
4030 if(!strncasecmp((const char*)cur,"UTF-8",5))
4031 {
4032 *charset = CD_CHARSET_UTF8;
4033 cur += 5;
4034 }
4035 else if(!strncasecmp((const char *)cur,"ISO-8859-1",10))
4036 {
4037 *charset = CD_CHARSET_ISO_9959_1;
4038 cur += 10;
4039 }
4040 else if(!strncasecmp((const char *)cur,"mime-charset",12))
4041 {
4042 *charset = CD_CHARSET_MIME;
4043 cur+=12;
4044 }
4045 else
4046 return -1;
4047 char_set = true;
4048 continue;
4049 }
4050 }
4051 else
4052 return -1;
4053 }
4054 break;
4055 case CD_STATE_LANGUAGE:
4056 {
4057 if(*cur == '\'')
4058 state = CD_STATE_EXT_VAL;
4059 }
4060 break;
4061 case CD_STATE_EXT_VAL:
4062 {
4063 if(!rfc5987_attr_char(*cur))
4064 {
4065 if(*cur == '%')
4066 {
4067 //Percent encoded, check if the next two digits are hex
4068 if(!fname_begin)
4069 fname_begin = cur;
4070 if( !(cur+2 < end && isxdigit(*++cur) && isxdigit(*++cur)))
4071 return -1;
4072 }
4073 else if(*cur == ';' || *cur == '\r' || *cur == '\n' || *cur == ' ' || *cur == '\t')
4074 {
4075 fname_end = cur;
4076 state = CD_STATE_FINAL;
4077 }
4078 }
4079 else
4080 {
4081 if(!fname_begin)
4082 fname_begin = cur;
4083 }
4084 }
4085 break;
4086 case CD_STATE_FINAL:
4087 {
4088 if(fname_begin && fname_end)
4089 {
4090 *fname_ptr = fname_begin;
4091 return fname_end-fname_begin;
4092 }
4093 }
4094 default:
4095 return -1;
4096 }
4097 cur++;
4098 }
4099 switch(state)
4100 {
4101 case CD_STATE_FINAL:
4102 case CD_STATE_VAL:
4103 case CD_STATE_EXT_VAL:
4104 {
4105 if(fname_begin)
4106 {
4107 *fname_ptr = fname_begin;
4108 if(!fname_end)
4109 fname_end = end;
4110 return fname_end-fname_begin;
4111 }
4112 }
4113 }
4114 return -1;
4115 }
4116
4117 static bool set_file_name_cd_header(u_char *start, u_char *end, void *ssn)
4118 {
4119 uint8_t unfold_buf[DECODE_BLEN] = {0};
4120 uint32_t unfold_size =0;
4121 int num_spaces = 0;
4122 u_char *p = start;
4123 u_char *fname = NULL;
4124 int len = 0;
4125 uint8_t charset = 0;
4126
4127 sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0 , &num_spaces);
4128 if(!unfold_size)
4129 return false;
4130
4131 if((len = extract_file_name(unfold_buf, unfold_size, &fname, &charset)) > 0 )
4132 {
4133 //Strip the size to 255 if bigger
4134 file_api->set_file_name(ssn, fname, len > 255 ? 255:len, true);
4135 return true;
4136 }
4137 return false;
4138 }
4139
4140 static inline bool is_boundary_present(const u_char *start, const u_char *end)
4141 {
4142 uint8_t unfold_buf[DECODE_BLEN] = {0};
4143 uint32_t unfold_size =0;
4144 int num_spaces = 0;
4145 const u_char *p = start;
4146 const char *BOUNDARY_STR = "boundary=";
4147
4148 sf_unfold_header(p, end-p, unfold_buf, sizeof(unfold_buf), &unfold_size, 0 , &num_spaces);
4149 if(!unfold_size)
4150 return false;
4151
4152 return SnortStrcasestr((const char *)unfold_buf, unfold_size, BOUNDARY_STR);
4153
4154 }
4155
4156 static inline int processPostFileData(HTTPINSPECT_GLOBAL_CONF *GlobalConf, Packet *p, HI_SESSION *Session, HttpSessionData *hsd)
4157 {
4158 const u_char *start = Session->client.request.content_type;
4159 const u_char *end = (Session->client.request.post_raw + Session->client.request.post_raw_size);
4160
4161 if ( !PacketHasPAFPayload(p) || (p->packet_flags & PKT_PSEUDO_FLUSH))
4162 return 0;
4163
4164 if ( hsd && start && is_boundary_present(start, end))
4165 {
4166 /* mime parsing
4167 * mime boundary should be processed before this
4168 */
4169 if (!hsd->mime_ssn)
4170 {
4171 hsd->mime_ssn = (MimeState *)SnortAlloc(sizeof(MimeState));
4172 if (!hsd->mime_ssn)
4173 return -1;
4174 hsd->mime_ssn->log_config = &(GlobalConf->mime_conf);
4175 hsd->mime_ssn->decode_conf = &(GlobalConf->decode_conf);
4176 hsd->mime_ssn->mime_mempool = mime_decode_mempool;
4177 hsd->mime_ssn->log_mempool = mime_log_mempool;
4178 /*Set log buffers per session*/
4179 if (file_api->set_log_buffers(&(hsd->mime_ssn->log_state),
4180 hsd->mime_ssn->log_config, hsd->mime_ssn->log_mempool, p->ssnptr, PP_HTTPINSPECT) < 0)
4181 {
4182 return -1;
4183 }
4184 }
4185 else
4186 {
4187 file_api->reset_mime_paf_state(&(hsd->mime_ssn->mime_boundary));
4188 }
4189
4190 file_api->process_mime_data(p, start, end, hsd->mime_ssn, 1, false,"HTTP", PP_HTTPINSPECT);
4191 }
4192 else
4193 {
4194 if (file_api->file_process(p,(uint8_t *)Session->client.request.post_raw,
4195 (uint16_t)Session->client.request.post_raw_size,
4196 file_api->get_file_position(p), true, false, false))
4197 {
4198 if( Session->client.request.content_disp )
4199 {
4200 if(!set_file_name_cd_header((u_char *)Session->client.request.content_disp,(u_char *)end, p->ssnptr))
4201 {
4202 setFileName(p);
4203 }
4204 }
4205 else
4206 {
4207 setFileName(p);
4208 }
4209 }
4210 }
4211 return 0;
4212 }
4213 static inline void processFileData(Packet *p, HttpSessionData *hsd, bool *fileProcessed)
4214 {
4215 if (*fileProcessed || !PacketHasPAFPayload(p))
4216 return;
4217
4218 if (hsd->mime_ssn)
4219 {
4220 uint8_t *end = ( uint8_t *)(p->data) + p->dsize;
4221 file_api->process_mime_data(p, p->data, end, hsd->mime_ssn, 1, false, "HTTP", PP_HTTPINSPECT);
4222 *fileProcessed = true;
4223 }
4224 else if (file_api->get_file_processed_size(p->ssnptr) >0)
4225 {
4226 file_api->file_process(p, (uint8_t *)p->data, p->dsize, file_api->get_file_position(p), true, false, false);
4227 *fileProcessed = true;
4228 }
4229 }
4230
4231 static inline int get_file_current_position(Packet *p,bool decomp_more,bool is_first)
4232 {
4233 int file_data_position = SNORT_FILE_POSITION_UNKNOWN;
4234 uint64_t processed_size = file_api->get_file_processed_size(p->ssnptr);
4235
4236 if(decomp_more)
4237 {
4238 if(is_first)
4239 {
4240 if(PacketHasStartOfPDU(p))
4241 file_data_position = SNORT_FILE_START;
4242 else if(processed_size)
4243 file_data_position = SNORT_FILE_MIDDLE;
4244 }
4245 else
4246 {
4247 if(processed_size)
4248 file_data_position = SNORT_FILE_MIDDLE;
4249 }
4250 }
4251 else
4252 {
4253 if(is_first)
4254 {
4255 file_data_position = file_api->get_file_position(p);
4256 }
4257 else
4258 {
4259 if(p->packet_flags & PKT_PDU_TAIL)
4260 file_data_position = SNORT_FILE_END;
4261 else if(processed_size)
4262 file_data_position = SNORT_FILE_MIDDLE;
4263 }
4264 }
4265 return file_data_position;
4266 }
4267
4268 char *convert_range_flag_to_str(uint16_t range_flag)
4269 {
4270 switch (range_flag)
4271 {
4272 case HTTP_RESP_RANGE_NONE:
4273 return "Range None";
4274 case RANGE_WITH_RESP_FULL_CONTENT:
4275 return "Full Content";
4276 case RANGE_WITH_RESP_PARTIAL_CONTENT:
4277 return "Partial Content";
4278 case RANGE_WITH_RESP_ERROR:
4279 return "Error in Range Field";
4280 case RANGE_WITH_RESP_NON_BYTE:
4281 return "Non-Byte unit";
4282 case RANGE_WITH_UNKNOWN_CONTENT_RANGE:
4283 return "Unknown Range Content";
4284 case RANGE_WITH_RESP_UNKNOWN_CONTENT_SIZE:
4285 return "Unknown Range Content Length";
4286 default:
4287 return "Skip Range";
4288 }
4289 }
4290
4291 /*
4292 ** NAME
4293 ** SnortHttpInspect::
4294 */
4295 /**
4296 ** This function calls the HttpInspect function that processes an HTTP
4297 ** session.
4298 **
4299 ** We need to instantiate a pointer for the HI_SESSION that HttpInspect
4300 ** fills in. Right now stateless processing fills in this session, which
4301 ** we then normalize, and eventually detect. We'll have to handle
4302 ** separately the normalization events, etc.
4303 **
4304 ** This function is where we can see from the highest level what the
4305 ** HttpInspect flow looks like.
4306 **
4307 ** @param GlobalConf pointer to the global configuration
4308 ** @param p pointer to the Packet structure
4309 **
4310 ** @return integer
4311 **
4312 ** @retval 0 function successful
4313 ** @retval <0 fatal error
4314 ** @retval >0 non-fatal error
4315 */
4316 #define HTTP_BUF_URI_FLAG 0x01
4317 #define HTTP_BUF_HEADER_FLAG 0x02
4318 #define HTTP_BUF_CLIENT_BODY_FLAG 0x04
4319 #define HTTP_BUF_METHOD_FLAG 0x08
4320 #define HTTP_BUF_COOKIE_FLAG 0x10
4321 #define HTTP_BUF_STAT_CODE 0x20
4322 #define HTTP_BUF_STAT_MSG 0x40
4323 int SnortHttpInspect(HTTPINSPECT_GLOBAL_CONF *GlobalConf, Packet *p)
4324 {
4325 HI_SESSION *Session;
4326 HI_SI_INPUT SiInput;
4327 int iInspectMode = 0;
4328 int iRet;
4329 int iCallDetect = 1;
4330 HttpSessionData *hsd = NULL;
4331 bool fileProcessed = false;
4332 bool is_first = true;
4333
4334 if (stream_api && stream_api->is_session_http2(p->ssnptr)
4335 && !(p->packet_flags & PKT_REBUILT_STREAM))
4336 {
4337 return 0;
4338 }
4339
4340 PROFILE_VARS;
4341
4342 if(!(stream_api->get_preproc_flags(p->ssnptr) & PP_HTTPINSPECT_PAF_FLUSH_POST_HDR))
4343 hi_stats.total++;
4344
4345 /*
4346 ** Set up the HI_SI_INPUT pointer. This is what the session_inspection()
4347 ** routines use to determine client and server traffic. Plus, this makes
4348 ** the HttpInspect library very independent from snort.
4349 */
4350 SetSiInput(&SiInput, p);
4351
4352 /*
4353 ** HTTPINSPECT PACKET FLOW::
4354 **
4355 ** Session Inspection Module::
4356 ** The Session Inspection Module retrieves the appropriate server
4357 ** configuration for sessions, and takes care of the stateless
4358 ** vs. stateful processing in order to do this. Once this module
4359 ** does it's magic, we're ready for the primetime.
4360 **
4361 ** HTTP Inspection Module::
4362 ** This isn't really a module in HttpInspect, but more of a helper
4363 ** function that sends the data to the appropriate inspection
4364 ** routine (client, server, anomalous server detection).
4365 **
4366 ** HTTP Normalization Module::
4367 ** This is where we normalize the data from the HTTP Inspection
4368 ** Module. The Normalization module handles what type of normalization
4369 ** to do (client, server).
4370 **
4371 ** HTTP Detection Module::
4372 ** This isn't being used in the first iteration of HttpInspect, but
4373 ** all the HTTP detection components of signatures will be.
4374 **
4375 ** HTTP Event Output Module::
4376 ** The Event Ouput Module handles any events that have been logged
4377 ** in the inspection, normalization, or detection phases.
4378 */
4379
4380 /*
4381 ** Session Inspection Module::
4382 */
4383 iRet = hi_si_session_inspection(GlobalConf, &Session, &SiInput, &iInspectMode, p);
4384 if (iRet)
4385 return iRet;
4386
4387 /* If no mode then we just look for anomalous servers if configured
4388 * to do so and get out of here */
4389 if (iInspectMode == HI_SI_NO_MODE)
4390 {
4391 /* Let's look for rogue HTTP servers and stuff */
4392 if (GlobalConf->anomalous_servers && (p->dsize > 5))
4393 {
4394 iRet = hi_server_anomaly_detection(Session, p->data, p->dsize);
4395 if (iRet)
4396 return iRet;
4397
4398 /*
4399 ** We log events before doing detection because every non-HTTP
4400 ** packet is possible an anomalous server. So we still want to
4401 ** go through the regular detection engine, and just log any
4402 ** alerts here before returning.
4403 **
4404 ** Return normally if this isn't either HTTP client or server
4405 ** traffic.
4406 */
4407 if (Session->anom_server.event_list.stack_count)
4408 LogEvents(Session, p, iInspectMode, NULL);
4409 }
4410
4411 return 0;
4412 }
4413
4414 hsd = GetHttpSessionData(p);
4415
4416 /*
4417 ** HI_EO_SERVER_PROTOCOL_OTHER alert added to detect 'SSH tunneling over HTTP',
4418 ** In SSH over HTTP evasion, first data message will always be 'HTTP response with SSH server
4419 ** version/banner' (without any client request). If the HTTP server response is the
4420 ** first message in http_session, this alert will be generated
4421 */
4422 if(!hsd && ( SiInput.pdir == HI_SI_SERVER_MODE ) && (p->packet_flags & PKT_STREAM_ORDER_OK))
4423 {
4424 if(p->ssnptr &&
4425 ((session_api->get_session_flags(p->ssnptr) &(SSNFLAG_SEEN_BOTH|SSNFLAG_MIDSTREAM)) == SSNFLAG_SEEN_BOTH))
4426 {
4427 if(hi_eo_generate_event(Session, HI_EO_SERVER_PROTOCOL_OTHER))
4428 {
4429 hi_eo_server_event_log(Session, HI_EO_SERVER_PROTOCOL_OTHER, NULL, NULL);
4430 }
4431 LogEvents(Session, p, iInspectMode, hsd);
4432 }
4433 }
4434
4435 if ( ScPafEnabled() &&
4436 (p->packet_flags & PKT_STREAM_INSERT) &&
4437 (!(p->packet_flags & PKT_PDU_TAIL)) )
4438 {
4439 int flow_depth;
4440
4441 if ( iInspectMode == HI_SI_CLIENT_MODE )
4442 {
4443 flow_depth = Session->server_conf->client_flow_depth;
4444 ApplyClientFlowDepth(p, flow_depth);
4445 }
4446 else
4447 {
4448 ApplyFlowDepth(Session->server_conf, p, hsd, 0, 1, GET_PKT_SEQ(p));
4449 }
4450
4451 p->packet_flags |= PKT_HTTP_DECODE;
4452 HttpLogFuncs(GlobalConf, hsd, p, iCallDetect);
4453
4454 if ( p->alt_dsize == 0 )
4455 {
4456 DisableDetect( p );
4457 EnablePreprocessor(p, PP_SDF);
4458 return 0;
4459 }
4460 // see comments on call to Detect() below
4461 PREPROC_PROFILE_START(hiDetectPerfStats);
4462 Detect(p);
4463 #ifdef PERF_PROFILING
4464 hiDetectCalled = 1;
4465 #endif
4466 PREPROC_PROFILE_END(hiDetectPerfStats);
4467 return 0;
4468 }
4469
4470 if (hsd == NULL)
4471 {
4472 hsd = SetNewHttpSessionData(p, (void *)Session);
4473 if (hsd == NULL)
4474 return 0;
4475 }
4476 else
4477 {
4478 /* Gzip data should not be logged with all the packets of the session.*/
4479 hsd->log_flags &= ~HTTP_LOG_GZIP_DATA;
4480 hsd->log_flags &= ~HTTP_LOG_JSNORM_DATA;
4481 }
4482
4483 /*
4484 ** HTTP Inspection Module::
4485 **
4486 ** This is where we do the client/server inspection and find the
4487 ** various HTTP protocol fields. We then normalize these fields and
4488 ** call the detection engine.
4489 **
4490 ** The reason for the loop is for pipelined requests. Doing pipelined
4491 ** requests in this way doesn't require any memory or tracking overhead.
4492 ** Instead, we just process each request linearly.
4493 */
4494 if (hsd->decomp_state)
4495 hsd->decomp_state->stage = HTTP_DECOMP_START;
4496 do
4497 {
4498 /*
4499 ** INIT:
4500 ** We set this equal to zero (again) because of the pipelining
4501 ** requests. We don't want to bail before we get to setting the
4502 ** URI, so we make sure here that this can't happen.
4503 */
4504 SetHttpDecode(0);
4505 ClearHttpBuffers();
4506
4507 iRet = hi_mi_mode_inspection(Session, iInspectMode, p, hsd);
4508 if (iRet)
4509 {
4510 if (hsd)
4511 {
4512 processFileData(p, hsd, &fileProcessed);
4513 }
4514 LogEvents(Session, p, iInspectMode, hsd);
4515 return iRet;
4516 }
4517
4518 iRet = hi_normalization(Session, iInspectMode, hsd);
4519 if (iRet)
4520 {
4521 LogEvents(Session, p, iInspectMode, hsd);
4522 return iRet;
4523 }
4524
4525 HttpLogFuncs(GlobalConf, hsd, p, iCallDetect);
4526
4527 /*
4528 ** Let's setup the pointers for the detection engine, and
4529 ** then go for it.
4530 */
4531 if ( iInspectMode == HI_SI_CLIENT_MODE )
4532 {
4533 const HttpBuffer* hb;
4534 ClearHttpBuffers(); // FIXTHIS needed here and right above??
4535 #ifdef DUMP_BUFFER
4536 clearReqBuffers();
4537 clearRespBuffers();
4538 #endif
4539 if ( Session->client.request.uri_norm )
4540 {
4541 SetHttpBufferEncoding(
4542 HTTP_BUFFER_URI,
4543 Session->client.request.uri_norm,
4544 Session->client.request.uri_norm_size,
4545 Session->client.request.uri_encode_type);
4546
4547 SetHttpBuffer(
4548 HTTP_BUFFER_RAW_URI,
4549 Session->client.request.uri,
4550 Session->client.request.uri_size);
4551
4552 p->packet_flags |= PKT_HTTP_DECODE;
4553 #ifdef DUMP_BUFFER
4554 dumpBuffer(URI_DUMP, Session->client.request.uri_norm, Session->client.request.uri_norm_size);
4555 #endif
4556
4557 }
4558 else if ( Session->client.request.uri )
4559 {
4560 SetHttpBufferEncoding(
4561 HTTP_BUFFER_URI,
4562 Session->client.request.uri,
4563 Session->client.request.uri_size,
4564 Session->client.request.uri_encode_type);
4565
4566 SetHttpBuffer(
4567 HTTP_BUFFER_RAW_URI,
4568 Session->client.request.uri,
4569 Session->client.request.uri_size);
4570
4571 p->packet_flags |= PKT_HTTP_DECODE;
4572 #ifdef DUMP_BUFFER
4573 dumpBuffer(RAW_URI_DUMP, Session->client.request.uri, Session->client.request.uri_size);
4574 #endif
4575 }
4576
4577 if ( Session->client.request.header_norm ||
4578 Session->client.request.header_raw )
4579 {
4580 if ( Session->client.request.header_norm )
4581 {
4582 SetHttpBufferEncoding(
4583 HTTP_BUFFER_HEADER,
4584 Session->client.request.header_norm,
4585 Session->client.request.header_norm_size,
4586 Session->client.request.header_encode_type);
4587
4588 SetHttpBuffer(
4589 HTTP_BUFFER_RAW_HEADER,
4590 Session->client.request.header_raw,
4591 Session->client.request.header_raw_size);
4592
4593 p->packet_flags |= PKT_HTTP_DECODE;
4594 #ifdef DUMP_BUFFER
4595 dumpBuffer(REQ_HEADER_DUMP, Session->client.request.header_norm, Session->client.request.header_norm_size);
4596 #endif
4597
4598 #ifdef DEBUG
4599 hi_stats.req_header_len += Session->client.request.header_norm_size;
4600 #endif
4601 }
4602 else
4603 {
4604 SetHttpBufferEncoding(
4605 HTTP_BUFFER_HEADER,
4606 Session->client.request.header_raw,
4607 Session->client.request.header_raw_size,
4608 Session->client.request.header_encode_type);
4609
4610 SetHttpBuffer(
4611 HTTP_BUFFER_RAW_HEADER,
4612 Session->client.request.header_raw,
4613 Session->client.request.header_raw_size);
4614
4615 p->packet_flags |= PKT_HTTP_DECODE;
4616 #ifdef DUMP_BUFFER
4617 dumpBuffer(RAW_REQ_HEADER_DUMP, Session->client.request.header_raw, Session->client.request.header_raw_size);
4618 #endif
4619 }
4620 }
4621
4622 if(Session->client.request.method & (HI_POST_METHOD | HI_GET_METHOD))
4623 {
4624 if(Session->client.request.post_raw)
4625 {
4626 if(processPostFileData(GlobalConf, p, Session, hsd) != 0)
4627 return 0;
4628
4629 if(Session->server_conf->post_depth > -1)
4630 {
4631 if(Session->server_conf->post_depth &&
4632 ((int)Session->client.request.post_raw_size > Session->server_conf->post_depth))
4633 {
4634 Session->client.request.post_raw_size = Session->server_conf->post_depth;
4635 }
4636 SetHttpBufferEncoding(
4637 HTTP_BUFFER_CLIENT_BODY,
4638 Session->client.request.post_raw,
4639 Session->client.request.post_raw_size,
4640 Session->client.request.post_encode_type);
4641
4642 p->packet_flags |= PKT_HTTP_DECODE;
4643 #ifdef DUMP_BUFFER
4644 dumpBuffer(CLIENT_BODY_DUMP, Session->client.request.post_raw, Session->client.request.post_raw_size);
4645 #endif
4646 }
4647
4648 }
4649 }
4650 else if (hsd)
4651 {
4652 processFileData(p, hsd, &fileProcessed);
4653 }
4654
4655 if ( Session->client.request.method_raw )
4656 {
4657 SetHttpBuffer(
4658 HTTP_BUFFER_METHOD,
4659 Session->client.request.method_raw,
4660 Session->client.request.method_size);
4661
4662 p->packet_flags |= PKT_HTTP_DECODE;
4663 #ifdef DUMP_BUFFER
4664 dumpBuffer(METHOD_DUMP, Session->client.request.method_raw, Session->client.request.method_size);
4665 #endif
4666 }
4667
4668 if ( Session->client.request.cookie_norm ||
4669 Session->client.request.cookie.cookie )
4670 {
4671 if ( Session->client.request.cookie_norm )
4672 {
4673 SetHttpBufferEncoding(
4674 HTTP_BUFFER_COOKIE,
4675 Session->client.request.cookie_norm,
4676 Session->client.request.cookie_norm_size,
4677 Session->client.request.cookie_encode_type);
4678
4679 SetHttpBuffer(
4680 HTTP_BUFFER_RAW_COOKIE,
4681 Session->client.request.cookie.cookie,
4682 Session->client.request.cookie.cookie_end -
4683 Session->client.request.cookie.cookie);
4684
4685 p->packet_flags |= PKT_HTTP_DECODE;
4686 #ifdef DUMP_BUFFER
4687 dumpBuffer(COOKIE_DUMP, Session->client.request.cookie_norm, Session->client.request.cookie_norm_size);
4688 #endif
4689 }
4690 else
4691 {
4692 SetHttpBufferEncoding(
4693 HTTP_BUFFER_COOKIE,
4694 Session->client.request.cookie.cookie,
4695 Session->client.request.cookie.cookie_end -
4696 Session->client.request.cookie.cookie,
4697 Session->client.request.cookie_encode_type);
4698
4699 SetHttpBuffer(
4700 HTTP_BUFFER_RAW_COOKIE,
4701 Session->client.request.cookie.cookie,
4702 Session->client.request.cookie.cookie_end -
4703 Session->client.request.cookie.cookie);
4704
4705 p->packet_flags |= PKT_HTTP_DECODE;
4706 #ifdef DUMP_BUFFER
4707 dumpBuffer(RAW_COOKIE_DUMP, Session->client.request.cookie.cookie, Session->client.request.cookie.cookie_end - Session->client.request.cookie.cookie);
4708 #endif
4709 }
4710 }
4711 else if ( !Session->server_conf->enable_cookie &&
4712 (hb = GetHttpBuffer(HTTP_BUFFER_HEADER)) )
4713 {
4714 SetHttpBufferEncoding(
4715 HTTP_BUFFER_COOKIE, hb->buf, hb->length, hb->encode_type);
4716
4717 hb = GetHttpBuffer(HTTP_BUFFER_RAW_HEADER);
4718 assert(hb);
4719
4720 SetHttpBuffer(HTTP_BUFFER_RAW_COOKIE, hb->buf, hb->length);
4721 #ifdef DUMP_BUFFER
4722 dumpBuffer(RAW_COOKIE_DUMP, hb->buf, hb->length);
4723 #endif
4724 p->packet_flags |= PKT_HTTP_DECODE;
4725 }
4726
4727 if ( IsLimitedDetect(p) )
4728 {
4729 ApplyClientFlowDepth(p, Session->server_conf->client_flow_depth);
4730
4731 if( !GetHttpBufferMask() && (p->alt_dsize == 0) )
4732 {
4733 DisableDetect( p );
4734 EnablePreprocessor(p, PP_SDF);
4735 return 0;
4736 }
4737 }
4738
4739 if (Session->client.request.range_flag != HTTP_RANGE_NONE)
4740 {
4741 if (Session->client.request.method != HI_GET_METHOD)
4742 {
4743 if (hi_eo_generate_event(Session, HI_EO_CLIENT_RANGE_NON_GET_METHOD))
4744 {
4745 hi_eo_client_event_log(Session, HI_EO_CLIENT_RANGE_NON_GET_METHOD, NULL, NULL);
4746 }
4747 }
4748 else
4749 {
4750 if (Session->client.request.range_flag == RANGE_WITH_REQ_ERROR)
4751 {
4752 if (hi_eo_generate_event(Session, HI_EO_CLIENT_RANGE_FIELD_ERROR))
4753 {
4754 hi_eo_client_event_log(Session, HI_EO_CLIENT_RANGE_FIELD_ERROR, NULL, NULL);
4755 }
4756 }
4757 }
4758 }
4759 }
4760 else /* Server mode */
4761 {
4762 const HttpBuffer* hb;
4763
4764 /*
4765 ** We check here to see whether this was a server response
4766 ** header or not. If the header size is 0 then, we know that this
4767 ** is not the header and don't do any detection.
4768 */
4769 #if defined(FEAT_OPEN_APPID)
4770 if( !(Session->server_conf->inspect_response || Session->server_conf->appid_enabled) &&
4771 #else
4772 if( !(Session->server_conf->inspect_response) &&
4773 #endif /* defined(FEAT_OPEN_APPID) */
4774 IsLimitedDetect(p) && !p->alt_dsize )
4775 {
4776 DisableDetect( p );
4777 EnablePreprocessor(p, PP_SDF);
4778 if(Session->server_conf->server_flow_depth == -1)
4779 {
4780 EnablePreprocessor(p, PP_DCE2);
4781 }
4782 return 0;
4783 }
4784 ClearHttpBuffers();
4785
4786 if ( Session->server.response.header_norm ||
4787 Session->server.response.header_raw )
4788 {
4789 if ( Session->server.response.header_norm )
4790 {
4791 SetHttpBufferEncoding(
4792 HTTP_BUFFER_HEADER,
4793 Session->server.response.header_norm,
4794 Session->server.response.header_norm_size,
4795 Session->server.response.header_encode_type);
4796
4797 SetHttpBuffer(
4798 HTTP_BUFFER_RAW_HEADER,
4799 Session->server.response.header_raw,
4800 Session->server.response.header_raw_size);
4801 #ifdef DUMP_BUFFER
4802 dumpBuffer(RESP_HEADER_DUMP, Session->server.response.header_norm, Session->server.response.header_norm_size);
4803 #endif
4804 }
4805 else
4806 {
4807 SetHttpBuffer(
4808 HTTP_BUFFER_HEADER,
4809 Session->server.response.header_raw,
4810 Session->server.response.header_raw_size);
4811
4812 SetHttpBuffer(
4813 HTTP_BUFFER_RAW_HEADER,
4814 Session->server.response.header_raw,
4815 Session->server.response.header_raw_size);
4816 #ifdef DUMP_BUFFER
4817 dumpBuffer(RAW_RESP_HEADER_DUMP, Session->server.response.header_raw, Session->server.response.header_raw_size);
4818 #endif
4819 }
4820 }
4821
4822 if ( Session->server.response.cookie_norm ||
4823 Session->server.response.cookie.cookie )
4824 {
4825 if(Session->server.response.cookie_norm )
4826 {
4827 SetHttpBufferEncoding(
4828 HTTP_BUFFER_COOKIE,
4829 Session->server.response.cookie_norm,
4830 Session->server.response.cookie_norm_size,
4831 Session->server.response.cookie_encode_type);
4832
4833 SetHttpBuffer(
4834 HTTP_BUFFER_RAW_COOKIE,
4835 Session->server.response.cookie.cookie,
4836 Session->server.response.cookie.cookie_end -
4837 Session->server.response.cookie.cookie);
4838 #ifdef DUMP_BUFFER
4839 dumpBuffer(RESP_COOKIE_DUMP, Session->server.response.cookie_norm, Session->server.response.cookie_norm_size);
4840 #endif
4841 }
4842 else
4843 {
4844 SetHttpBuffer(
4845 HTTP_BUFFER_COOKIE,
4846 Session->server.response.cookie.cookie,
4847 Session->server.response.cookie.cookie_end -
4848 Session->server.response.cookie.cookie);
4849
4850 SetHttpBuffer(
4851 HTTP_BUFFER_RAW_COOKIE,
4852 Session->server.response.cookie.cookie,
4853 Session->server.response.cookie.cookie_end -
4854 Session->server.response.cookie.cookie);
4855 #ifdef DUMP_BUFFER
4856 dumpBuffer(RAW_RESP_COOKIE_DUMP, Session->server.response.cookie.cookie, Session->server.response.cookie.cookie_end - Session->server.response.cookie.cookie);
4857 #endif
4858 }
4859 }
4860 else if ( !Session->server_conf->enable_cookie &&
4861 (hb = GetHttpBuffer(HTTP_BUFFER_HEADER)) )
4862 {
4863 SetHttpBufferEncoding(
4864 HTTP_BUFFER_COOKIE, hb->buf, hb->length, hb->encode_type);
4865
4866 hb = GetHttpBuffer(HTTP_BUFFER_RAW_HEADER);
4867 assert(hb);
4868
4869 SetHttpBuffer(HTTP_BUFFER_RAW_COOKIE, hb->buf, hb->length);
4870
4871 #ifdef DUMP_BUFFER
4872 dumpBuffer(RAW_RESP_COOKIE_DUMP, hb->buf, hb->length);
4873 #endif
4874 }
4875
4876 if(Session->server.response.status_code)
4877 {
4878 SetHttpBuffer(
4879 HTTP_BUFFER_STAT_CODE,
4880 Session->server.response.status_code,
4881 Session->server.response.status_code_size);
4882
4883 if (!strncmp((const char*)Session->server.response.status_code, "206", 3))
4884 {
4885 if ((Session->server.response.range_flag == RANGE_WITH_RESP_ERROR) &&
4886 hi_eo_generate_event(Session, HI_EO_SERVER_RANGE_FIELD_ERROR))
4887 {
4888 hi_eo_server_event_log(Session, HI_EO_SERVER_RANGE_FIELD_ERROR, NULL, NULL);
4889 }
4890
4891 if (Session->server.response.range_flag == HTTP_RESP_RANGE_NONE)
4892 {
4893 hsd->resp_state.look_for_partial_content = CONTENT_NONE;
4894 }
4895 else if (Session->server.response.range_flag == RANGE_WITH_RESP_FULL_CONTENT)
4896 {
4897 hsd->resp_state.look_for_partial_content = FULL_CONTENT;
4898 }
4899 else
4900 {
4901 hsd->resp_state.look_for_partial_content = PARTIAL_CONTENT;
4902 }
4903
4904 if ((Session->client.request.range_flag == HTTP_RANGE_WITH_FULL_CONTENT_REQ) &&
4905 ((Session->server.response.range_flag == RANGE_WITH_RESP_UNKNOWN_CONTENT_SIZE) ||
4906 (Session->server.response.range_flag == RANGE_WITH_UNKNOWN_CONTENT_RANGE) ||
4907 (Session->server.response.range_flag == RANGE_WITH_RESP_ERROR)))
4908 {
4909 hsd->resp_state.look_for_partial_content = FULL_CONTENT;
4910 }
4911 }
4912
4913 #ifdef DUMP_BUFFER
4914 dumpBuffer(STAT_CODE_DUMP, Session->server.response.status_code, Session->server.response.status_code_size);
4915 #endif
4916 }
4917
4918 if(Session->server.response.status_msg)
4919 {
4920 SetHttpBuffer(
4921 HTTP_BUFFER_STAT_MSG,
4922 Session->server.response.status_msg,
4923 Session->server.response.status_msg_size);
4924 #ifdef DUMP_BUFFER
4925 dumpBuffer(STAT_MSG_DUMP, Session->server.response.status_msg, Session->server.response.status_msg_size);
4926 #endif
4927 }
4928
4929 if(Session->server.response.body_raw_size > 0)
4930 {
4931 int detect_data_size = (int)Session->server.response.body_size;
4932
4933 /*body_size is included in the data_extracted*/
4934 if((Session->server_conf->server_flow_depth > 0) &&
4935 (hsd->resp_state.data_extracted < (Session->server_conf->server_flow_depth + (int)Session->server.response.body_raw_size)))
4936 {
4937 /*flow_depth is smaller than data_extracted, need to subtract*/
4938 if(Session->server_conf->server_flow_depth < hsd->resp_state.data_extracted)
4939 detect_data_size -= hsd->resp_state.data_extracted - Session->server_conf->server_flow_depth;
4940 }
4941 else if (Session->server_conf->server_flow_depth)
4942 {
4943 detect_data_size = 0;
4944 }
4945
4946 /* Do we have a file decompression object? */
4947 if( hsd->fd_state != 0 )
4948 {
4949 fd_status_t Ret_Code;
4950
4951 uint16_t Data_Len;
4952 const uint8_t *Data;
4953
4954 hsd->fd_state->Next_In = (uint8_t *) (Data = Session->server.response.body_raw);
4955 hsd->fd_state->Avail_In = (Data_Len = (uint16_t) detect_data_size);
4956
4957 (void)File_Decomp_SetBuf( hsd->fd_state );
4958
4959 Ret_Code = File_Decomp( hsd->fd_state );
4960
4961 if( Ret_Code == File_Decomp_DecompError )
4962 {
4963 Session->server.response.body = Data;
4964 Session->server.response.body_raw = Data;
4965 Session->server.response.body_size = Data_Len;
4966 Session->server.response.body_raw_size = Data_Len;
4967
4968 if(hi_eo_generate_event(Session, hsd->fd_state->Error_Event))
4969 {
4970 hi_eo_server_event_log(Session, hsd->fd_state->Error_Event, NULL, NULL);
4971 }
4972 File_Decomp_StopFree( hsd->fd_state );
4973 hsd->fd_state = NULL;
4974 }
4975 /* If we didn't find a Sig, then clear the File_Decomp state
4976 and don't keep looking. */
4977 else if( Ret_Code == File_Decomp_NoSig )
4978 {
4979 File_Decomp_StopFree( hsd->fd_state );
4980 hsd->fd_state = NULL;
4981 }
4982 else
4983 {
4984 Session->server.response.body = hsd->fd_state->Buffer;
4985 Session->server.response.body_size = (DECODE_BLEN - hsd->fd_state->Avail_Out);
4986 Session->server.response.body_raw = Data;
4987 Session->server.response.body_raw_size = Data_Len;
4988 }
4989
4990 setFileDataPtr(Session->server.response.body, (uint16_t)Session->server.response.body_size);
4991 #ifdef DUMP_BUFFER
4992 dumpBuffer(FILE_DATA_DUMP, Session->server.response.body, (uint16_t)Session->server.response.body_size);
4993 #endif
4994 }
4995 else
4996 {
4997 setFileDataPtr(Session->server.response.body, (uint16_t)detect_data_size);
4998 #ifdef DUMP_BUFFER
4999 dumpBuffer(FILE_DATA_DUMP, Session->server.response.body, (uint16_t)detect_data_size);
5000 #endif
5001 }
5002
5003 if (ScPafEnabled() && PacketHasPAFPayload(p) && !(p->packet_flags & PKT_PSEUDO_FLUSH))
5004 {
5005 bool decomp_more = (hsd->decomp_state && hsd->decomp_state->stage == HTTP_DECOMP_MID)?true:false;
5006 char *pfile_type = NULL;
5007
5008 int file_data_position = get_file_current_position(p,decomp_more,is_first);
5009
5010 if (file_data_position == SNORT_FILE_POSITION_UNKNOWN && hsd->resp_state.eoh_found)
5011 {
5012 file_data_position = SNORT_FILE_START;
5013 }
5014 if (file_api->file_process(p, (uint8_t *)Session->server.response.body_raw,
5015 (uint16_t)Session->server.response.body_raw_size,
5016 file_data_position, false, false, false))
5017 {
5018 setFileName(p);
5019 }
5020 if (GlobalConf->normalize_nulls)
5021 {
5022 /* Call File API to get the file type */
5023 pfile_type = file_api->file_get_filetype (p->ssnptr);
5024 if (pfile_type)
5025 {
5026 if (SnortStrcasestr(pfile_type,strlen(pfile_type), "Unknown" ) ||
5027 SnortStrcasestr(pfile_type,strlen(pfile_type), "RTF" ))
5028 {
5029
5030 Session->server.response.body_size = NormalizeRandomNulls(
5031 (uint8_t*) Session->server.response.body,
5032 Session->server.response.body_size,
5033 (uint8_t*) Session->server.response.body);
5034 }
5035 }
5036 }
5037 }
5038 is_first = false;
5039 #ifdef DUMP_BUFFER
5040 dumpBuffer(RESP_BODY_DUMP, Session->server.response.body_raw, Session->server.response.body_raw_size);
5041 #endif
5042 }
5043
5044 if( IsLimitedDetect(p) &&
5045 !GetHttpBufferMask() && (p->alt_dsize == 0) )
5046 {
5047 DisableDetect( p );
5048 EnablePreprocessor(p, PP_SDF);
5049 if(Session->server_conf->server_flow_depth == -1)
5050 {
5051 EnablePreprocessor(p, PP_DCE2);
5052 }
5053 return 0;
5054 }
5055 }
5056
5057 /*
5058 ** If we get here we either had a client or server request/response.
5059 ** We do the detection here, because we're starting a new paradigm
5060 ** about protocol decoders.
5061 **
5062 ** Protocol decoders are now their own detection engine, since we are
5063 ** going to be moving protocol field detection from the generic
5064 ** detection engine into the protocol module. This idea scales much
5065 ** better than having all these Packet struct field checks in the
5066 ** main detection engine for each protocol field.
5067 */
5068 PREPROC_PROFILE_START(hiDetectPerfStats);
5069 Detect(p);
5070 #ifdef PERF_PROFILING
5071 hiDetectCalled = 1;
5072 #endif
5073 PREPROC_PROFILE_END(hiDetectPerfStats);
5074
5075 /*
5076 ** Handle event stuff after we do detection.
5077 **
5078 ** Here's the reason why:
5079 ** - since snort can only handle one logged event per packet,
5080 ** we only log HttpInspect events if there wasn't one in the
5081 ** detection engine. I say that events generated in the
5082 ** "advanced generic content matching" engine is more
5083 ** important than generic events that I can log here.
5084 */
5085 LogEvents(Session, p, iInspectMode, hsd);
5086
5087 /*
5088 ** We set the global detection flag here so that if request pipelines
5089 ** fail, we don't do any detection.
5090 */
5091 iCallDetect = 0;
5092
5093 #ifdef PPM_MGR
5094 /*
5095 ** Check PPM here to ensure decompression loop doesn't spin indefinitely
5096 */
5097 if( PPM_PKTS_ENABLED() )
5098 {
5099 PPM_GET_TIME();
5100 PPM_PACKET_TEST();
5101
5102 if( PPM_PACKET_ABORT_FLAG() )
5103 return 0;
5104 }
5105 #endif
5106 } while(Session->client.request.pipeline_req || (hsd->decomp_state && hsd->decomp_state->stage == HTTP_DECOMP_MID));
5107
5108 if ( iCallDetect == 0 )
5109 {
5110 /* Detect called at least once from above pkt processing loop. */
5111 DisableAllDetect( p );
5112
5113 /* dcerpc2 preprocessor may need to look at this for
5114 * RPC over HTTP setup */
5115 EnablePreprocessor(p, PP_DCE2);
5116
5117 /* sensitive_data preprocessor may look for PII over HTTP */
5118 EnablePreprocessor(p, PP_SDF);
5119 }
5120
5121 return 0;
5122 }
5123
5124 int HttpInspectInitializeGlobalConfig(HTTPINSPECT_GLOBAL_CONF *config,
5125 char *ErrorString, int iErrStrLen)
5126 {
5127 int iRet;
5128
5129 if (config == NULL)
5130 {
5131 snprintf(ErrorString, iErrStrLen, "Global configuration is NULL.");
5132 return -1;
5133 }
5134
5135 iRet = hi_ui_config_init_global_conf(config);
5136 if (iRet)
5137 {
5138 snprintf(ErrorString, iErrStrLen,
5139 "Error initializing Global Configuration.");
5140 return -1;
5141 }
5142
5143 iRet = hi_client_init(config);
5144 if (iRet)
5145 {
5146 snprintf(ErrorString, iErrStrLen,
5147 "Error initializing client module.");
5148 return -1;
5149 }
5150
5151 file_api->set_mime_decode_config_defauts(&(config->decode_conf));
5152 file_api->set_mime_log_config_defauts(&(config->mime_conf));
5153
5154 RegisterGetHttpXffFields(getHttpXffFields);
5155 session_api->register_get_http_xff_precedence(getHttpXffPrecedence);
5156
5157 return 0;
5158 }
5159
5160 HttpSessionData * SetNewHttpSessionData(Packet *p, void *data)
5161 {
5162 HttpSessionData *hsd;
5163
5164 if (p->ssnptr == NULL)
5165 return NULL;
5166
5167 hi_stats.session_count++;
5168
5169 hsd = (HttpSessionData *)SnortAlloc(sizeof(HttpSessionData));
5170 hi_stats.mem_used += (sizeof(HttpSessionData) + sizeof(DECOMPRESS_STATE) + sizeof(HTTP_LOG_STATE));
5171 init_decode_utf_state(&hsd->utf_state);
5172
5173 session_api->set_application_data(p->ssnptr, PP_HTTPINSPECT, hsd, FreeHttpSessionData);
5174
5175 hsd->fd_state = (fd_session_p_t)NULL;
5176 hsd->resp_state.eoh_found = false;
5177 hsd->resp_state.look_for_partial_content = CONTENT_NONE;
5178 hsd->resp_state.chunk_len_state = CHUNK_LEN_DEFAULT;
5179
5180 return hsd;
5181 }
5182
5183 void FreeHttpSessionData(void *data)
5184 {
5185 HttpSessionData *hsd = (HttpSessionData *)data;
5186
5187 if (hsd == NULL)
5188 return;
5189 hi_stats.session_count--;
5190
5191 if (hsd->decomp_state != NULL)
5192 {
5193 inflateEnd(&(hsd->decomp_state->d_stream));
5194 mempool_free(hi_gzip_mempool, hsd->decomp_state->bkt);
5195 }
5196
5197 if (hsd->log_state != NULL)
5198 {
5199 mempool_free(http_mempool, hsd->log_state->log_bucket);
5200 free(hsd->log_state);
5201 }
5202
5203 while(hsd->tList_start != NULL )
5204 deleteNode_tList(hsd);
5205
5206 file_api->free_mime_session(hsd->mime_ssn);
5207
5208 if( hsd->fd_state != 0 )
5209 {
5210 File_Decomp_StopFree(hsd->fd_state); // Stop & Stop & Free fd session object
5211 hsd->fd_state = NULL; // ...just for good measure
5212 }
5213
5214 hi_stats.mem_used -= (sizeof(HttpSessionData) + sizeof(DECOMPRESS_STATE) + sizeof(HTTP_LOG_STATE));
5215 free(hsd);
5216 }
5217
5218 int GetHttpTrueIP(void *data, uint8_t **buf, uint32_t *len, uint32_t *type)
5219 {
5220 sfaddr_t *true_ip;
5221
5222 true_ip = GetTrueIPForSession(data);
5223 if(!true_ip)
5224 return 0;
5225
5226 if(sfaddr_family(true_ip) == AF_INET6)
5227 {
5228 *type = EVENT_INFO_XFF_IPV6;
5229 *len = sizeof(struct in6_addr); /*ipv6 address size in bytes*/
5230 *buf = (uint8_t*)sfaddr_get_ip6_ptr(true_ip);
5231 }
5232 else
5233 {
5234 *type = EVENT_INFO_XFF_IPV4;
5235 *len = sizeof(struct in_addr); /*ipv4 address size in bytes*/
5236 *buf = (uint8_t*)sfaddr_get_ip4_ptr(true_ip);
5237 }
5238
5239 return 1;
5240 }
5241
5242 int IsGzipData(void *data)
5243 {
5244 HttpSessionData *hsd = NULL;
5245
5246 if (data == NULL)
5247 return -1;
5248 hsd = (HttpSessionData *)session_api->get_application_data(data, PP_HTTPINSPECT);
5249
5250 if(hsd == NULL)
5251 return -1;
5252
5253 if((hsd->log_flags & HTTP_LOG_GZIP_DATA) && (file_data_ptr.len > 0 ))
5254 return 0;
5255 else
5256 return -1;
5257 }
5258
5259
5260 int GetHttpGzipData(void *data, uint8_t **buf, uint32_t *len, uint32_t *type)
5261 {
5262 if(!IsGzipData(data))
5263 {
5264 *buf = (uint8_t*)file_data_ptr.data;
5265 *len = file_data_ptr.len;
5266 *type = EVENT_INFO_GZIP_DATA;
5267 return 1;
5268 }
5269
5270 return 0;
5271
5272 }
5273
5274 int IsJSNormData(void *data)
5275 {
5276 HttpSessionData *hsd = NULL;
5277
5278 if (data == NULL)
5279 return -1;
5280 hsd = (HttpSessionData *)session_api->get_application_data(data, PP_HTTPINSPECT);
5281
5282 if(hsd == NULL)
5283 return -1;
5284
5285 if((hsd->log_flags & HTTP_LOG_JSNORM_DATA) && (file_data_ptr.len > 0 ))
5286 return 0;
5287 else
5288 return -1;
5289
5290 }
5291
5292 int GetHttpJSNormData(void *data, uint8_t **buf, uint32_t *len, uint32_t *type)
5293 {
5294 if(!IsJSNormData(data))
5295 {
5296 *buf = (uint8_t*) file_data_ptr.data;
5297 *len = file_data_ptr.len;
5298 *type = EVENT_INFO_JSNORM_DATA;
5299 return 1;
5300 }
5301
5302 return 0;
5303 }
5304
5305 int GetHttpUriData(void *data, uint8_t **buf, uint32_t *len, uint32_t *type)
5306 {
5307 HttpSessionData *hsd = NULL;
5308
5309 if (data == NULL)
5310 return 0;
5311 hsd = (HttpSessionData *)session_api->get_application_data(data, PP_HTTPINSPECT);
5312
5313 if(hsd == NULL)
5314 return 0;
5315
5316 if(hsd->log_state && hsd->log_state->uri_bytes > 0)
5317 {
5318 *buf = hsd->log_state->uri_extracted;
5319 *len = hsd->log_state->uri_bytes;
5320 *type = EVENT_INFO_HTTP_URI;
5321 return 1;
5322 }
5323
5324 return 0;
5325 }
5326
5327
5328 int GetHttpHostnameData(void *data, uint8_t **buf, uint32_t *len, uint32_t *type)
5329 {
5330 HttpSessionData *hsd = NULL;
5331
5332 if (data == NULL)
5333 return 0;
5334 hsd = (HttpSessionData *)session_api->get_application_data(data, PP_HTTPINSPECT);
5335
5336 if(hsd == NULL)
5337 return 0;
5338
5339 if(hsd->log_state && hsd->log_state->hostname_bytes > 0)
5340 {
5341 *buf = hsd->log_state->hostname_extracted;
5342 *len = hsd->log_state->hostname_bytes;
5343 *type = EVENT_INFO_HTTP_HOSTNAME;
5344 return 1;
5345 }
5346
5347 return 0;
5348 }
5349
5350 void HI_SearchInit(void)
5351 {
5352 const HiSearchToken *tmp;
5353 hi_javascript_search_mpse = search_api->search_instance_new();
5354 if (hi_javascript_search_mpse == NULL)
5355 {
5356 FatalError("%s(%d) Could not allocate memory for HTTP <script> tag search.\n",
5357 __FILE__, __LINE__);
5358 }
5359 for (tmp = &hi_patterns[0]; tmp->name != NULL; tmp++)
5360 {
5361 hi_js_search[tmp->search_id].name = tmp->name;
5362 hi_js_search[tmp->search_id].name_len = tmp->name_len;
5363 search_api->search_instance_add(hi_javascript_search_mpse, tmp->name, tmp->name_len, tmp->search_id);
5364 }
5365 search_api->search_instance_prep(hi_javascript_search_mpse);
5366
5367 hi_htmltype_search_mpse = search_api->search_instance_new();
5368 if (hi_htmltype_search_mpse == NULL)
5369 {
5370 FatalError("%s(%d) Could not allocate memory for HTTP <script> type search.\n",
5371 __FILE__, __LINE__);
5372 }
5373 for (tmp = &html_patterns[0]; tmp->name != NULL; tmp++)
5374 {
5375 hi_html_search[tmp->search_id].name = tmp->name;
5376 hi_html_search[tmp->search_id].name_len = tmp->name_len;
5377 search_api->search_instance_add(hi_htmltype_search_mpse, tmp->name, tmp->name_len, tmp->search_id);
5378 }
5379 search_api->search_instance_prep(hi_htmltype_search_mpse);
5380 }
5381
5382 void HI_SearchFree(void)
5383 {
5384 if (hi_javascript_search_mpse != NULL)
5385 search_api->search_instance_free(hi_javascript_search_mpse);
5386
5387 if (hi_htmltype_search_mpse != NULL)
5388 search_api->search_instance_free(hi_htmltype_search_mpse);
5389 }
5390
5391 int HI_SearchStrFound(void *id, void *unused, int index, void *data, void *unused2)
5392 {
5393 int search_id = (int)(uintptr_t)id;
5394
5395 hi_search_info.id = search_id;
5396 hi_search_info.index = index;
5397 hi_search_info.length = hi_current_search[search_id].name_len;
5398
5399 /* Returning non-zero stops search, which is okay since we only look for one at a time */
5400 return 1;
5401 }
5402
5403 bool GetHttpFastBlockingStatus()
5404 {
5405 HTTPINSPECT_GLOBAL_CONF *http_conf = NULL;
5406 tSfPolicyId policyId = getNapRuntimePolicy();
5407
5408 sfPolicyUserPolicySet(hi_config, policyId);
5409 http_conf = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(hi_config);
5410
5411 return(http_conf->fast_blocking);
5412 }
5413
5414 static int GetHttpInspectConf( void *ssn, uint32_t flags, HTTPINSPECT_CONF **serverConf, HTTPINSPECT_CONF **clientConf )
5415 {
5416 int iRet = HI_SUCCESS;
5417 tSfPolicyId policyId = getNapRuntimePolicy();
5418 HTTPINSPECT_GLOBAL_CONF *pPolicyConfig = NULL;
5419 HI_SI_INPUT SiInput;
5420 int iInspectMode = 0;
5421 SessionControlBlock *scb = (SessionControlBlock *)ssn;
5422 sfPolicyUserPolicySet (hi_config, policyId);
5423 pPolicyConfig = (HTTPINSPECT_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(hi_config);
5424 if( !scb )
5425 return iRet;
5426
5427 SiInput.pdir = HI_SI_NO_MODE;
5428
5429 if( flags & PKT_FROM_CLIENT )
5430 {
5431 SiInput.pdir = HI_SI_CLIENT_MODE;
5432
5433 IP_COPY_VALUE(SiInput.sip, &scb->client_ip);
5434 IP_COPY_VALUE(SiInput.dip, &scb->server_ip);
5435
5436 SiInput.sport = ntohs(scb->client_port);
5437 SiInput.dport = ntohs(scb->server_port);
5438 }
5439 else if ( flags & PKT_FROM_SERVER )
5440 {
5441 SiInput.pdir = HI_SI_SERVER_MODE;
5442
5443 IP_COPY_VALUE(SiInput.sip, &scb->server_ip);
5444 IP_COPY_VALUE(SiInput.dip, &scb->client_ip);
5445
5446 SiInput.sport = ntohs(scb->server_port);
5447 SiInput.dport = ntohs(scb->client_port);
5448 }
5449
5450 iRet = GetHttpConf(pPolicyConfig, serverConf, clientConf, &SiInput, &iInspectMode, ssn);
5451 return iRet;
5452 }
5453
5454 static char** getHttpXffPrecedence(void* ssn, uint32_t flags, int* nFields)
5455 {
5456 HTTPINSPECT_CONF *serverConf = NULL;
5457 HTTPINSPECT_CONF *clientConf = NULL;
5458
5459 GetHttpInspectConf(ssn, flags, &serverConf, &clientConf);
5460
5461 if (!serverConf || !serverConf->xff_headers[0])
5462 {
5463 if (nFields) *nFields = 0;
5464 return NULL;
5465 }
5466
5467 if (nFields)
5468 {
5469 for ((*nFields) = 0; ((*nFields) < HTTP_MAX_XFF_FIELDS) && serverConf->xff_headers[*nFields]; (*nFields)++)
5470 ;
5471 }
5472 return (char**)serverConf->xff_headers;
5473 }
5474
5475 int GetHttpFlowDepth(void *ssn, uint32_t flags)
5476 {
5477 HTTPINSPECT_CONF *serverConf = 0;
5478 HTTPINSPECT_CONF *clientConf = 0;
5479 int flow_depth = 0;
5480
5481 GetHttpInspectConf( ssn, flags, &serverConf, &clientConf );
5482 if( !serverConf )
5483 return flow_depth;
5484
5485 if( serverConf->file_policy )
5486 {
5487 flow_depth = 0;
5488 }
5489 else if( flags & PKT_FROM_CLIENT )
5490 {
5491 //Only for POST
5492 flow_depth = serverConf->post_depth;
5493 }
5494 else if( flags & PKT_FROM_SERVER )
5495 {
5496 flow_depth = serverConf->server_flow_depth;
5497 }
5498 return flow_depth;
5499 }
5500
5501 uint8_t isHttpRespPartialCont(void *data)
5502 {
5503 HttpSessionData *hsd = NULL;
5504
5505 if (data == NULL) {
5506 return CONTENT_NONE;
5507 }
5508
5509 hsd = (HttpSessionData *)session_api->get_application_data(data, PP_HTTPINSPECT);
5510 if (hsd == NULL) {
5511 return CONTENT_NONE;
5512 }
5513
5514 return hsd->resp_state.look_for_partial_content;
5515 }