"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/preprocessors/snort_httpinspect.c" (16 Oct 2020, 170058 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "snort_httpinspect.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

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