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