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