Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

snort_httpinspect.c

Go to the documentation of this file.
00001 /**
00002 **  @file       snort_httpinspect.c
00003 **
00004 **  @author     Daniel Roelker <droelker@sourcefire.com>
00005 **
00006 **  @brief      This file wraps the HttpInspect functionality for Snort
00007 **              and starts the HttpInspect flow.
00008 **
00009 **  Copyright (C) 2003-2005 Sourcefire,Inc.
00010 **
00011 **  The file takes a Packet structure from the Snort IDS to start the
00012 **  HttpInspect flow.  This also uses the Stream Interface Module which
00013 **  is also Snort-centric.  Mainly, just a wrapper to HttpInspect               
00014 **  functionality, but a key part to starting the basic flow.
00015 **
00016 **  The main bulk of this file is taken up with user configuration and
00017 **  parsing.  The reason this is so large is because HttpInspect takes
00018 **  very detailed configuration parameters for each specified server.
00019 **  Hopefully every web server that is out there can be emulated
00020 **  with these configuration options.
00021 **  
00022 **  The main functions of note are:
00023 **    - HttpInspectSnortConf::this is the configuration portion
00024 **    - SnortHttpInspect::this is the actual inspection flow
00025 **    - LogEvents:this is where we log the HttpInspect events
00026 **
00027 **  NOTES:
00028 **
00029 **  - 2.11.03:  Initial Development.  DJR
00030 **  - 2.4.05:   Added tab_uri_delimiter config option.  AJM.
00031 */
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <sys/types.h>
00035 #ifndef WIN32
00036 #include <sys/socket.h>
00037 #include <netinet/in.h>
00038 #include <arpa/inet.h>
00039 #endif
00040 
00041 #include "snort.h"
00042 #include "detect.h"
00043 #include "decode.h"
00044 #include "log.h"
00045 #include "event.h"
00046 #include "generators.h"
00047 #include "debug.h"
00048 #include "plugbase.h"
00049 #include "util.h"
00050 #include "event_queue.h"
00051 #include "stream.h"
00052 
00053 #include "hi_return_codes.h"
00054 #include "hi_ui_config.h"
00055 #include "hi_ui_iis_unicode_map.h"
00056 #include "hi_si.h"
00057 #include "hi_mi.h"
00058 #include "hi_norm.h"
00059 
00060 extern PV pv;
00061 
00062 #define MAX_FILENAME    1000
00063 
00064 /**
00065 **  The definition of the configuration separators in the snort.conf
00066 **  configure line.
00067 */
00068 #define CONF_SEPARATORS " \t\n\r"
00069 
00070 /*
00071 **  These are the definitions of the parser section delimiting 
00072 **  keywords to configure HttpInspect.  When one of these keywords
00073 **  are seen, we begin a new section.
00074 */
00075 #define GLOBAL        "global"
00076 #define GLOBAL_SERVER "global_server"
00077 #define SERVER        "server"
00078 
00079 /*
00080 **  GLOBAL subkeywords.
00081 */
00082 /**
00083 **  Takes an integer arugment
00084 */
00085 #define MAX_PIPELINE  "max_pipeline"
00086 /**
00087 **  Specifies whether to alert on anomalous
00088 **  HTTP servers or not.
00089 */
00090 #define ANOMALOUS_SERVERS "detect_anomalous_servers"
00091 /**
00092 **  Alert on general proxy use
00093 */
00094 #define PROXY_ALERT "proxy_alert"
00095 /**
00096 **  Takes an inspection type argument
00097 **  stateful or stateless
00098 */
00099 #define INSPECT_TYPE  "inspection_type"
00100 #define DEFAULT       "default"
00101 
00102 /*
00103 **  GLOBAL subkeyword values
00104 */
00105 #define INSPECT_TYPE_STATELESS "stateless"
00106 #define INSPECT_TYPE_STATEFUL  "stateful"
00107 
00108 /*
00109 **  SERVER subkeywords.
00110 */
00111 #define PORTS             "ports"
00112 #define FLOW_DEPTH        "flow_depth"
00113 #define IIS_UNICODE_MAP   "iis_unicode_map"
00114 #define CHUNK_LENGTH      "chunk_length"
00115 #define PIPELINE          "no_pipeline_req"
00116 #define ASCII             "ascii"
00117 #define DOUBLE_DECODE     "double_decode"
00118 #define U_ENCODE          "u_encode"
00119 #define BARE_BYTE         "bare_byte"
00120 #define BASE36            "base36"
00121 #define UTF_8             "utf_8"
00122 #define IIS_UNICODE       "iis_unicode"
00123 #define NON_RFC_CHAR      "non_rfc_char"
00124 #define MULTI_SLASH       "multi_slash"
00125 #define IIS_BACKSLASH     "iis_backslash"
00126 #define DIRECTORY         "directory"
00127 #define APACHE_WS         "apache_whitespace"
00128 #define IIS_DELIMITER     "iis_delimiter"
00129 #define PROFILE           "profile"
00130 #define NON_STRICT        "non_strict"
00131 #define ALLOW_PROXY       "allow_proxy_use"
00132 #define OVERSIZE_DIR      "oversize_dir_length"
00133 #define INSPECT_URI_ONLY  "inspect_uri_only"
00134 #define GLOBAL_ALERT      "no_alerts"
00135 #define WEBROOT           "webroot"
00136 #define TAB_URI_DELIMITER "tab_uri_delimiter"
00137 
00138 /*
00139 **  Alert subkeywords
00140 */
00141 #define BOOL_YES     "yes"
00142 #define BOOL_NO      "no"
00143 
00144 /*
00145 **  PROFILE subkeywords
00146 */
00147 #define APACHE        "apache"
00148 #define IIS           "iis"
00149 #define ALL           "all"
00150 
00151 /*
00152 **  Port list delimiters
00153 */
00154 #define START_PORT_LIST "{"
00155 #define END_PORT_LIST   "}"
00156 
00157 /*
00158 **  Keyword for the default server configuration
00159 */
00160 #define SERVER_DEFAULT "default"
00161 
00162 /*
00163 **  NAME
00164 **    ProcessGlobalAlert::
00165 */
00166 /**
00167 **  Process the global alert keyword.
00168 **
00169 **  There is no arguments to this keyword, because you can only turn
00170 **  all the alerts off.  As of now, we aren't going to support turning
00171 **  all the alerts on.
00172 **
00173 **  @param GlobalConf  pointer to the global configuration
00174 **  @param ErrorString error string buffer
00175 **  @param ErrStrLen   the lenght of the error string buffer
00176 **
00177 **  @return an error code integer 
00178 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00179 **
00180 **  @retval  0 successs
00181 **  @retval -1 generic fatal error
00182 **  @retval  1 generic non-fatal error
00183 */
00184 /*
00185 static int ProcessGlobalAlert(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
00186                               char *ErrorString, int ErrStrLen)
00187 {
00188     GlobalConf->no_alerts = 1;
00189 
00190     return 0;
00191 }
00192 */
00193 
00194 /* 
00195 **  NAME
00196 **    ProcessMaxPipeline::
00197 */
00198 /**
00199 **  Process the max pipeline configuration.
00200 **
00201 **  This sets the maximum number of pipeline requests that we
00202 **  will buffer while waiting for responses, before inspection.
00203 **  There is a maximum limit on this, but we can track a user
00204 **  defined amount.
00205 **
00206 **  @param GlobalConf  pointer to the global configuration
00207 **  @param ErrorString error string buffer
00208 **  @param ErrStrLen   the lenght of the error string buffer
00209 **
00210 **  @return an error code integer 
00211 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00212 **
00213 **  @retval  0 successs
00214 **  @retval -1 generic fatal error
00215 **  @retval  1 generic non-fatal error
00216 */
00217 static int ProcessMaxPipeline(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
00218                               char *ErrorString, int ErrStrLen)
00219 {
00220     char *pcToken;
00221     char *pcEnd = NULL;
00222 
00223     pcToken = strtok(NULL, CONF_SEPARATORS);
00224     if(pcToken == NULL)
00225     {
00226         snprintf(ErrorString, ErrStrLen,
00227                 "No argument to token '%s'.", MAX_PIPELINE);
00228 
00229         return -1;
00230     }
00231 
00232     GlobalConf->max_pipeline_requests = strtol(pcToken, &pcEnd, 10);
00233 
00234     /*
00235     **  Let's check to see if the entire string was valid.
00236     **  If there is an address here, then there was an
00237     **  invalid character in the string.
00238     */
00239     if(*pcEnd)
00240     {
00241         snprintf(ErrorString, ErrStrLen,
00242                 "Invalid argument to token '%s'.  Must be a positive "
00243                 "number between 0 and %d.", MAX_PIPELINE,
00244                 HI_UI_CONFIG_MAX_PIPE);
00245 
00246         return -1;
00247     }
00248 
00249     if(GlobalConf->max_pipeline_requests < 0 || 
00250        GlobalConf->max_pipeline_requests > HI_UI_CONFIG_MAX_PIPE)
00251     {
00252         snprintf(ErrorString, ErrStrLen,
00253                 "Invalid argument to token '%s'.  Must be a positive "
00254                 "number between 0 and %d.", MAX_PIPELINE, HI_UI_CONFIG_MAX_PIPE);
00255 
00256         return -1;
00257     }
00258 
00259     return 0;
00260 }
00261 
00262 /* 
00263 **  NAME
00264 **    ProcessInspectType::
00265 */
00266 /**
00267 **  Process the type of inspection.
00268 **
00269 **  This sets the type of inspection for HttpInspect to do.
00270 **
00271 **  @param GlobalConf  pointer to the global configuration
00272 **  @param ErrorString error string buffer
00273 **
00274 **  @param ErrStrLen   the lenght of the error string buffer
00275 **
00276 **  @return an error code integer 
00277 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00278 **
00279 **  @retval  0 successs
00280 **  @retval -1 generic fatal error
00281 **  @retval  1 generic non-fatal error
00282 */
00283 static int ProcessInspectType(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
00284                               char *ErrorString, int ErrStrLen)
00285 {
00286     char *pcToken;
00287 
00288     pcToken = strtok(NULL, CONF_SEPARATORS);
00289     if(pcToken == NULL)
00290     {
00291         snprintf(ErrorString, ErrStrLen,
00292                 "No argument to token '%s'.", INSPECT_TYPE);
00293 
00294         return -1;
00295     }
00296 
00297     if(!strcmp(INSPECT_TYPE_STATEFUL, pcToken))
00298     {
00299         GlobalConf->inspection_type = HI_UI_CONFIG_STATEFUL;
00300 
00301         /*
00302         **  We don't support this option yet, so we'll give an error and
00303         **  bail.
00304         */
00305         snprintf(ErrorString, ErrStrLen,
00306                  "Stateful HttpInspect processing is not yet available.  "
00307                  "Please use stateless processing for now.");
00308 
00309         return -1;
00310     }
00311     else if(!strcmp(INSPECT_TYPE_STATELESS, pcToken))
00312     {
00313         GlobalConf->inspection_type = HI_UI_CONFIG_STATELESS;
00314     }
00315     else
00316     {
00317         snprintf(ErrorString, ErrStrLen,
00318                 "Invalid argument to token '%s'.  Must be either "
00319                 "'%s' or '%s'.", INSPECT_TYPE, INSPECT_TYPE_STATEFUL,
00320                 INSPECT_TYPE_STATELESS);
00321 
00322         return -1;
00323     }
00324 
00325     return 0;
00326 }
00327 
00328 static int ProcessIISUnicodeMap(int **iis_unicode_map, 
00329                                 char **iis_unicode_map_filename,
00330                                 int *iis_unicode_map_codepage,
00331                                 char *ErrorString, int ErrStrLen)
00332 {
00333     char *pcToken;
00334     int  iRet;
00335     char filename[MAX_FILENAME];
00336     char *pcEnd;
00337     int  iCodeMap;
00338 
00339     pcToken = strtok(NULL, CONF_SEPARATORS);
00340     if(pcToken == NULL)
00341     {
00342         snprintf(ErrorString, ErrStrLen,
00343                  "No argument to token '%s'.", IIS_UNICODE_MAP);
00344 
00345         return -1;
00346     }
00347 
00348     /*
00349     **  If an absolute path is specified, then use that.
00350     */
00351 #ifndef WIN32
00352     if(pcToken[0] == '/')
00353     {
00354         iRet = snprintf(filename, sizeof(filename), "%s", pcToken);
00355     }
00356     else
00357     {
00358         /*
00359         **  Set up the file name directory
00360         */
00361         if(pv.config_dir[strlen(pv.config_dir)-1] == '/')
00362         {
00363             iRet = snprintf(filename, sizeof(filename), 
00364                             "%s%s", pv.config_dir, pcToken);
00365         }
00366         else
00367         {
00368             iRet = snprintf(filename, sizeof(filename),
00369                             "%s/%s", pv.config_dir, pcToken);
00370         }
00371     }
00372 #else
00373     if(strlen(pcToken)>3 && pcToken[1]==':' && pcToken[2]=='\\')
00374     {
00375         iRet = snprintf(filename, sizeof(filename), "%s", pcToken);
00376     }
00377     else
00378     {
00379         /*
00380         **  Set up the file name directory
00381         */
00382         if(pv.config_dir[strlen(pv.config_dir)-1] == '\\' ||
00383            pv.config_dir[strlen(pv.config_dir)-1] == '/' )
00384         {
00385             iRet = snprintf(filename, sizeof(filename), 
00386                             "%s%s", pv.config_dir, pcToken);
00387         }
00388         else
00389         {
00390             iRet = snprintf(filename, sizeof(filename),
00391                             "%s\\%s", pv.config_dir, pcToken);
00392         }
00393     }
00394 #endif
00395 
00396     if(iRet < 0)
00397     {
00398         snprintf(ErrorString, ErrStrLen,
00399                  "Filename too long for token '%s'.", IIS_UNICODE_MAP);
00400 
00401         return -1;
00402     }
00403 
00404     /*
00405     **  Set the filename
00406     */
00407     *iis_unicode_map_filename = strdup(filename);
00408     if(*iis_unicode_map_filename == NULL)
00409     {
00410         snprintf(ErrorString, ErrStrLen,
00411                  "Could not strdup() '%s' filename.",
00412                  IIS_UNICODE_MAP);
00413 
00414         return -1;
00415     }
00416 
00417     pcToken = strtok(NULL, CONF_SEPARATORS);
00418     if(pcToken == NULL)
00419     {
00420         snprintf(ErrorString, ErrStrLen,
00421                  "No codemap to select from IIS Unicode Map file.");
00422 
00423         return -1;
00424     }
00425 
00426     /*
00427     **  Grab the unicode codemap to use
00428     */
00429     iCodeMap = strtol(pcToken, &pcEnd, 10);
00430     if(*pcEnd || iCodeMap < 0)
00431     {
00432         snprintf(ErrorString, ErrStrLen,
00433                  "Invalid IIS codemap argument.");
00434 
00435         return -1;
00436     }
00437 
00438     /*
00439     **  Set the codepage
00440     */
00441     *iis_unicode_map_codepage = iCodeMap;
00442 
00443     /*
00444     **  Assume that the pcToken we now have is the filename of the map
00445     **  table.
00446     */
00447     if((iRet = hi_ui_parse_iis_unicode_map(iis_unicode_map, 
00448                                            filename, iCodeMap)))
00449     {
00450         if(iRet == HI_INVALID_FILE)
00451         {
00452             snprintf(ErrorString, ErrStrLen,
00453                      "Unable to open the IIS Unicode Map file '%s'.",
00454                      filename);
00455         }
00456         else if(iRet == HI_FATAL_ERR)
00457         {
00458             snprintf(ErrorString, ErrStrLen,
00459                      "Did not find specified IIS Unicode codemap in "
00460                      "the specified IIS Unicode Map file.");
00461         }
00462         else
00463         {
00464             snprintf(ErrorString, ErrStrLen,
00465                      "There was an error while parsing the IIS Unicode "
00466                      "Map file.");
00467         }
00468 
00469         return -1;
00470     }
00471 
00472     return 0;
00473 }
00474 
00475 static int ProcessOversizeDir(HTTPINSPECT_CONF *ServerConf,
00476                               char *ErrorString, int ErrStrLen)
00477 {
00478     char *pcToken;
00479     char *pcEnd;
00480     int  iDirLen;
00481 
00482     pcToken = strtok(NULL, CONF_SEPARATORS);
00483     if(pcToken == NULL)
00484     {
00485         snprintf(ErrorString, ErrStrLen,
00486                  "No argument to token '%s'.", OVERSIZE_DIR);
00487 
00488         return -1;
00489     }
00490 
00491     /*
00492     **  Grab the oversize directory length
00493     */
00494     iDirLen = strtol(pcToken, &pcEnd, 10);
00495     if(*pcEnd || iDirLen < 0)
00496     {
00497         snprintf(ErrorString, ErrStrLen,
00498                  "Invalid argument to token '%s'.", OVERSIZE_DIR);
00499         
00500         return -1;
00501     }
00502 
00503     ServerConf->long_dir = iDirLen;
00504 
00505     return 0;
00506 }
00507 
00508 /*
00509 **  NAME
00510 **      ProcessGlobalConf::
00511 */
00512 /**
00513 **  This is where we process the global configuration for HttpInspect.
00514 **
00515 **  We set the values of the global configuraiton here.  Any errors that
00516 **  are encountered are specified in the error string and the type of
00517 **  error is returned through the return code, i.e. fatal, non-fatal.
00518 **
00519 **  The configuration options that are dealt with here are:
00520 **      - global_alert
00521 **          This tells us whether to do any internal alerts or not, on
00522 **          a global scale.
00523 **      - max_pipeline
00524 **          Tells HttpInspect how many pipeline requests to buffer looking
00525 **          for a response before inspection.
00526 **      - inspection_type
00527 **          What type of inspection for HttpInspect to do, stateless or
00528 **          stateful.
00529 **
00530 **  @param GlobalConf  pointer to the global configuration
00531 **  @param ErrorString error string buffer
00532 **  @param ErrStrLen   the lenght of the error string buffer
00533 **
00534 **  @return an error code integer 
00535 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00536 **
00537 **  @retval  0 successs
00538 **  @retval -1 generic fatal error
00539 **  @retval  1 generic non-fatal error
00540 */
00541 static int ProcessGlobalConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
00542                              char *ErrorString, int ErrStrLen)
00543 {
00544     int  iRet;
00545     char *pcToken;
00546     int  iTokens = 0;
00547 
00548     while((pcToken = strtok(NULL, CONF_SEPARATORS)))
00549     {
00550         /*
00551         **  Show that we at least got one token
00552         */
00553         iTokens = 1;
00554 
00555         /*
00556         **  Search for configuration keywords
00557         */
00558         if(!strcmp(MAX_PIPELINE, pcToken))
00559         {
00560             if((iRet = ProcessMaxPipeline(GlobalConf, ErrorString, ErrStrLen)))
00561             {
00562                 return iRet;
00563             }
00564         }
00565         else if(!strcmp(INSPECT_TYPE, pcToken))
00566         {
00567             if((iRet = ProcessInspectType(GlobalConf, ErrorString, ErrStrLen)))
00568             {
00569                 return iRet;
00570             }
00571         }
00572         else if(!strcmp(IIS_UNICODE_MAP, pcToken))
00573         {
00574             if((iRet = ProcessIISUnicodeMap(&GlobalConf->iis_unicode_map,
00575                                          &GlobalConf->iis_unicode_map_filename,
00576                                             &GlobalConf->iis_unicode_codepage,
00577                                             ErrorString,ErrStrLen)))
00578             {
00579                 return iRet;
00580             }
00581         }
00582         else if(!strcmp(ANOMALOUS_SERVERS, pcToken))
00583         {
00584             /*
00585             **  This is easy to configure since we just look for the token
00586             **  and turn on the option.
00587             */
00588             GlobalConf->anomalous_servers = 1;
00589         }
00590         else if(!strcmp(PROXY_ALERT, pcToken))
00591         {
00592             GlobalConf->proxy_alert = 1;
00593         }
00594         else
00595         {
00596             snprintf(ErrorString, ErrStrLen,
00597                     "Invalid keyword '%s' for '%s' configuration.", 
00598                      pcToken, GLOBAL);
00599 
00600             return -1;
00601         }
00602     }
00603 
00604     /*
00605     **  If there are not any tokens to the configuration, then
00606     **  we let the user know and log the error.  return non-fatal
00607     **  error.
00608     */
00609     if(!iTokens)
00610     {
00611         snprintf(ErrorString, ErrStrLen,
00612                 "No tokens to '%s' configuration.", GLOBAL);
00613 
00614         return -1;
00615     }
00616 
00617     /*
00618     **  Let's check to make sure that we get a default IIS Unicode Codemap
00619     */
00620     if(!GlobalConf->iis_unicode_map)
00621     {
00622         snprintf(ErrorString, ErrStrLen,
00623                  "Global configuration must contain an IIS Unicode Map "
00624                  "configuration.  Use token '%s'.", IIS_UNICODE_MAP);
00625 
00626         return -1;
00627     }
00628 
00629     return 0;
00630 }
00631 
00632 /*
00633 **  NAME
00634 **    ProcessProfile::
00635 */
00636 /**
00637 **  Process the PROFILE configuration.
00638 **
00639 **  This function verifies that the argument to the profile configuration
00640 **  is valid.  We also check to make sure there is no additional
00641 **  configuration after the PROFILE.  This is no allowed, so we
00642 **  alert on that fact.
00643 **
00644 **  @param ServerConf  pointer to the server configuration
00645 **  @param ErrorString error string buffer
00646 **  @param ErrStrLen   the length of the error string buffer
00647 **
00648 **  @return an error code integer 
00649 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00650 **
00651 **  @retval  0 successs
00652 **  @retval -1 generic fatal error
00653 **  @retval  1 generic non-fatal error
00654 */
00655 static int ProcessProfile(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
00656                           HTTPINSPECT_CONF *ServerConf,
00657                           char *ErrorString, int ErrStrLen)
00658 {
00659     char *pcToken;
00660     int  iRet;
00661 
00662     pcToken = strtok(NULL, CONF_SEPARATORS);
00663     if(pcToken == NULL)
00664     {
00665         snprintf(ErrorString, ErrStrLen,
00666                 "No argument to '%s'.", PROFILE);
00667 
00668         return -1;
00669     }
00670 
00671     /*
00672     **  Load the specific type of profile
00673     */
00674     if(!strcmp(APACHE, pcToken))
00675     {
00676         if((iRet = hi_ui_config_set_profile_apache(ServerConf)))
00677         {
00678             if(iRet == HI_MEM_ALLOC_FAIL)
00679             {
00680                 snprintf(ErrorString, ErrStrLen,
00681                         "Memory allocation failed while setting the '%s' "
00682                         "profile.", APACHE);
00683 
00684                 return -1;
00685             }
00686             else
00687             {
00688                 snprintf(ErrorString, ErrStrLen,
00689                         "Undefined error code for set_profile_apache.");
00690 
00691                 return -1;
00692             }
00693         }
00694     }
00695     else if(!strcmp(IIS, pcToken))
00696     {
00697         if((iRet = hi_ui_config_set_profile_iis(ServerConf, 
00698                                                 GlobalConf->iis_unicode_map)))
00699         {
00700             if(iRet == HI_MEM_ALLOC_FAIL)
00701             {
00702                 snprintf(ErrorString, ErrStrLen,
00703                         "Memory allocation failed while setting the '%s' "
00704                         "profile.", IIS);
00705 
00706                 return -1;
00707             }
00708             else
00709             {
00710                 snprintf(ErrorString, ErrStrLen,
00711                         "Undefined error code for set_profile_iis.");
00712 
00713                 return -1;
00714             }
00715         }
00716     }
00717     else if(!strcmp(ALL, pcToken))
00718     {
00719         if((iRet = hi_ui_config_set_profile_all(ServerConf,
00720                                                 GlobalConf->iis_unicode_map)))
00721         {
00722             if(iRet == HI_MEM_ALLOC_FAIL)
00723             {
00724                 snprintf(ErrorString, ErrStrLen,
00725                         "Memory allocation failed while setting the '%s' "
00726                         "profile.", ALL);
00727 
00728                 return -1;
00729             }
00730             else
00731             {
00732                 snprintf(ErrorString, ErrStrLen,
00733                         "Undefined error code for set_profile_all.");
00734 
00735                 return -1;
00736             }
00737         }
00738     }
00739     else
00740     {
00741         snprintf(ErrorString, ErrStrLen,
00742                 "Invalid profile argument '%s'.", pcToken);
00743 
00744         return -1;
00745     }
00746 
00747     return 0;
00748 }
00749 
00750 /*
00751 **  NAME
00752 **    ProcessPorts::
00753 */
00754 /**
00755 **  Process the port list for the server configuration.
00756 **
00757 **  This configuration is a list of valid ports and is ended by a 
00758 **  delimiter.
00759 **
00760 **  @param ServerConf  pointer to the server configuration
00761 **  @param ErrorString error string buffer
00762 **  @param ErrStrLen   the length of the error string buffer
00763 **
00764 **  @return an error code integer 
00765 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00766 **
00767 **  @retval  0 successs
00768 **  @retval -1 generic fatal error
00769 **  @retval  1 generic non-fatal error
00770 */
00771 static int ProcessPorts(HTTPINSPECT_CONF *ServerConf,
00772                         char *ErrorString, int ErrStrLen)
00773 {
00774     char *pcToken;
00775     char *pcEnd;
00776     int  iPort;
00777     int  iEndPorts = 0;
00778 
00779     pcToken = strtok(NULL, CONF_SEPARATORS);
00780     if(!pcToken)
00781     {
00782         snprintf(ErrorString, ErrStrLen,
00783                 "Invalid port list format.");
00784 
00785         return -1;
00786     }
00787 
00788     if(strcmp(START_PORT_LIST, pcToken))
00789     {
00790         snprintf(ErrorString, ErrStrLen,
00791                 "Must start a port list with the '%s' token.",
00792                 START_PORT_LIST);
00793 
00794         return -1;
00795     }
00796     
00797     while((pcToken = strtok(NULL, CONF_SEPARATORS)))
00798     {
00799         if(!strcmp(END_PORT_LIST, pcToken))
00800         {
00801             iEndPorts = 1;
00802             break;
00803         }
00804 
00805         iPort = strtol(pcToken, &pcEnd, 10);
00806 
00807         /*
00808         **  Validity check for port
00809         */
00810         if(*pcEnd)
00811         {
00812             snprintf(ErrorString, ErrStrLen,
00813                     "Invalid port number.");
00814 
00815             return -1;
00816         }
00817 
00818         if(iPort < 0 || iPort > 65535)
00819         {
00820             snprintf(ErrorString, ErrStrLen,
00821                     "Invalid port number.  Must be between 0 and "
00822                     "65535.");
00823 
00824             return -1;
00825         }
00826 
00827         ServerConf->ports[iPort] = 1;
00828 
00829         if(ServerConf->port_count < 65536)
00830             ServerConf->port_count++;
00831     }
00832 
00833     if(!iEndPorts)
00834     {
00835         snprintf(ErrorString, ErrStrLen,
00836                 "Must end '%s' configuration with '%s'.",
00837                 PORTS, END_PORT_LIST);
00838 
00839         return -1;
00840     }
00841 
00842     return 0;
00843 }
00844 
00845 /*
00846 **  NAME
00847 **    ProcessFlowDepth::
00848 */
00849 /**
00850 **  Configure the flow depth for a server.
00851 **
00852 **  Check that the value for flow depth is within bounds
00853 **  and is a valid number.
00854 **
00855 **  @param ServerConf  pointer to the server configuration
00856 **  @param ErrorString error string buffer
00857 **  @param ErrStrLen   the length of the error string buffer
00858 **
00859 **  @return an error code integer 
00860 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00861 **
00862 **  @retval  0 successs
00863 **  @retval -1 generic fatal error
00864 **  @retval  1 generic non-fatal error
00865 */
00866 static int ProcessFlowDepth(HTTPINSPECT_CONF *ServerConf,
00867                             char *ErrorString, int ErrStrLen)
00868 {
00869     char *pcToken;
00870     int  iFlowDepth;
00871     char *pcEnd;
00872 
00873     pcToken = strtok(NULL, CONF_SEPARATORS);
00874     if(pcToken == NULL)
00875     {
00876         snprintf(ErrorString, ErrStrLen,
00877                 "No argument to '%s' token.", FLOW_DEPTH);
00878 
00879         return -1;
00880     }
00881 
00882     iFlowDepth = strtol(pcToken, &pcEnd, 10);
00883     if(*pcEnd)
00884     {
00885         snprintf(ErrorString, ErrStrLen,
00886                 "Invalid argument to '%s'.", FLOW_DEPTH);
00887 
00888         return -1;
00889     }
00890 
00891     /* -1 here is okay, which means ignore ALL server side traffic */
00892     if(iFlowDepth < -1 || iFlowDepth > 1460)
00893     {
00894         snprintf(ErrorString, ErrStrLen,
00895                 "Invalid argument to '%s'.  Must be between 0 and "
00896                 "1460.", FLOW_DEPTH);
00897 
00898         return -1;
00899     }
00900 
00901     ServerConf->flow_depth = iFlowDepth;
00902 
00903     return 0;
00904 }
00905 
00906 /*
00907 **  NAME
00908 **    ProcessChunkLength::
00909 */
00910 /**
00911 **  Process and verify the chunk length for the server configuration.
00912 **  
00913 **  @param ServerConf  pointer to the server configuration
00914 **  @param ErrorString error string buffer
00915 **  @param ErrStrLen   the length of the error string buffer
00916 **
00917 **  @return an error code integer 
00918 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00919 **
00920 **  @retval  0 successs
00921 **  @retval -1 generic fatal error
00922 **  @retval  1 generic non-fatal error
00923 */
00924 static int ProcessChunkLength(HTTPINSPECT_CONF *ServerConf,
00925                               char *ErrorString, int ErrStrLen)
00926 {
00927     char *pcToken;
00928     int  iChunkLength;
00929     char *pcEnd;
00930 
00931     pcToken = strtok(NULL, CONF_SEPARATORS);
00932     if(pcToken == NULL)
00933     {
00934         snprintf(ErrorString, ErrStrLen,
00935                 "No argument to '%s' token.", CHUNK_LENGTH);
00936 
00937         return -1;
00938     }
00939 
00940     iChunkLength = strtol(pcToken, &pcEnd, 10);
00941     if(*pcEnd)
00942     {
00943         snprintf(ErrorString, ErrStrLen,
00944                 "Invalid argument to '%s'.", CHUNK_LENGTH);
00945 
00946         return -1;
00947     }
00948 
00949     if(iChunkLength < 0)
00950     {
00951         snprintf(ErrorString, ErrStrLen,
00952                 "Invalid argument to '%s'.", CHUNK_LENGTH);
00953 
00954         return -1;
00955     }
00956 
00957     ServerConf->chunk_length = iChunkLength;
00958 
00959     return 0;
00960 }
00961 
00962 /*
00963 **  NAME
00964 **    ProcessConfOpt::
00965 */
00966 /**
00967 **  Set the CONF_OPT on and alert fields.
00968 **
00969 **  We check to make sure of valid parameters and then
00970 **  set the appropriate fields.  Not much more to it, than
00971 **  that.
00972 **
00973 **  @param ConfOpt  pointer to the configuration option
00974 **  @param Option   character pointer to the option being configured
00975 **  @param ErrorString error string buffer
00976 **  @param ErrStrLen   the length of the error string buffer
00977 **
00978 **  @return an error code integer 
00979 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
00980 **
00981 **  @retval  0 successs
00982 **  @retval -1 generic fatal error
00983 **  @retval  1 generic non-fatal error
00984 */
00985 static int ProcessConfOpt(HTTPINSPECT_CONF_OPT *ConfOpt, char *Option,
00986                           char *ErrorString, int ErrStrLen)
00987 {
00988     char *pcToken;
00989 
00990     pcToken = strtok(NULL, CONF_SEPARATORS);
00991     if(pcToken == NULL)
00992     {
00993         snprintf(ErrorString, ErrStrLen,
00994                 "No argument to token '%s'.", Option);
00995 
00996         return -1;
00997     }
00998 
00999     /*
01000     **  Check for the alert value
01001     */
01002     if(!strcmp(BOOL_YES, pcToken))
01003     {
01004         ConfOpt->alert = 1;
01005     }
01006     else if(!strcmp(BOOL_NO, pcToken))
01007     {
01008         ConfOpt->alert = 0;
01009     }
01010     else
01011     {
01012         snprintf(ErrorString, ErrStrLen,
01013                 "Invalid argument to token '%s'.", Option);
01014 
01015         return -1;
01016     }
01017 
01018     ConfOpt->on = 1;
01019 
01020     return 0;
01021 }
01022 
01023 /*
01024 **  NAME
01025 **    ProcessNonRfcChar::
01026 */
01027 /***
01028 **  Configure any characters that the user wants alerted on in the
01029 **  URI.
01030 **
01031 **  This function allocates the memory for CONF_OPT per character and
01032 **  configures the alert option.
01033 **
01034 **  @param ConfOpt  pointer to the configuration option
01035 **  @param ErrorString error string buffer
01036 **  @param ErrStrLen   the length of the error string buffer
01037 **
01038 **  @return an error code integer 
01039 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
01040 **
01041 **  @retval  0 successs
01042 **  @retval -1 generic fatal error
01043 **  @retval  1 generic non-fatal error
01044 */
01045 static int ProcessNonRfcChar(HTTPINSPECT_CONF *ServerConf,
01046                              char *ErrorString, int ErrStrLen)
01047 {
01048     char *pcToken;
01049     char *pcEnd;
01050     int  iChar;
01051     int  iEndChar = 0;
01052 
01053     pcToken = strtok(NULL, CONF_SEPARATORS);
01054     if(!pcToken)
01055     {
01056         snprintf(ErrorString, ErrStrLen,
01057                 "Invalid '%s' list format.", NON_RFC_CHAR);
01058 
01059         return -1;
01060     }
01061 
01062     if(strcmp(START_PORT_LIST, pcToken))
01063     {
01064         snprintf(ErrorString, ErrStrLen,
01065                 "Must start a '%s' list with the '%s' token.",
01066                 NON_RFC_CHAR, START_PORT_LIST);
01067 
01068         return -1;
01069     }
01070     
01071     while((pcToken = strtok(NULL, CONF_SEPARATORS)))
01072     {
01073         if(!strcmp(END_PORT_LIST, pcToken))
01074         {
01075             iEndChar = 1;
01076             break;
01077         }
01078 
01079         iChar = strtol(pcToken, &pcEnd, 16);
01080         if(*pcEnd)
01081         {
01082             snprintf(ErrorString, ErrStrLen,
01083                     "Invalid argument to '%s'.  Must be a single "
01084                     "character.", NON_RFC_CHAR);
01085 
01086             return -1;
01087         }
01088 
01089         if(iChar < 0 || iChar > 255)
01090         {
01091             snprintf(ErrorString, ErrStrLen,
01092                     "Invalid character value to '%s'.  Must be a single "
01093                     "character no greater than 255.", NON_RFC_CHAR);
01094 
01095             return -1;
01096         }
01097 
01098         ServerConf->non_rfc_chars[iChar] = 1;
01099     }
01100 
01101     if(!iEndChar)
01102     {
01103         snprintf(ErrorString, ErrStrLen,
01104                 "Must end '%s' configuration with '%s'.",
01105                 NON_RFC_CHAR, END_PORT_LIST);
01106 
01107         return -1;
01108     }
01109 
01110     return 0;
01111 }
01112 
01113 /*
01114 **  NAME
01115 **    ProcessServerConf::
01116 */
01117 /**
01118 **  Process the global server configuration.
01119 **
01120 **  Take the configuration and translate into the global server
01121 **  configuration.  We also check for any configuration errors and
01122 **  invalid keywords.
01123 **
01124 **  @param ServerConf  pointer to the server configuration
01125 **  @param ErrorString error string buffer
01126 **  @param ErrStrLen   the length of the error string buffer
01127 **
01128 **  @return an error code integer 
01129 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
01130 **
01131 **  @retval  0 successs
01132 **  @retval -1 generic fatal error
01133 **  @retval  1 generic non-fatal error
01134 */
01135 static int ProcessServerConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
01136                              HTTPINSPECT_CONF *ServerConf,
01137                              char *ErrorString, int ErrStrLen)
01138 {
01139     char *pcToken;
01140     int  iRet;
01141     int  iPorts = 0;
01142     HTTPINSPECT_CONF_OPT *ConfOpt;
01143 
01144     /*
01145     **  Check for profile keyword first, it's the only place in the
01146     **  configuration that is correct.
01147     */
01148     pcToken = strtok(NULL, CONF_SEPARATORS);
01149     if(pcToken == NULL)
01150     {
01151         snprintf(ErrorString, ErrStrLen,
01152                 "No tokens to '%s' configuration.", GLOBAL);
01153 
01154         return 1;
01155     }
01156 
01157     if(!strcmp(PROFILE, pcToken))
01158     {
01159         if((iRet = ProcessProfile(GlobalConf, ServerConf,
01160                                   ErrorString, ErrStrLen)))
01161         {
01162             return iRet;
01163         }
01164 
01165         pcToken = strtok(NULL, CONF_SEPARATORS);
01166         if(pcToken == NULL)
01167         {
01168             snprintf(ErrorString, ErrStrLen,
01169                      "No port list to the profile token.");
01170 
01171             return -1;
01172         }
01173 
01174         do
01175         {
01176             if(!strcmp(PORTS, pcToken))
01177             {
01178                 if((iRet = ProcessPorts(ServerConf, 
01179                                         ErrorString, ErrStrLen)))
01180                 {
01181                     return iRet;
01182                 }
01183 
01184                 iPorts = 1;
01185             }
01186             else if(!strcmp(IIS_UNICODE_MAP, pcToken))
01187             {
01188                 if((iRet = ProcessIISUnicodeMap(&ServerConf->iis_unicode_map,
01189                                          &ServerConf->iis_unicode_map_filename,
01190                                              &ServerConf->iis_unicode_codepage,
01191                                                 ErrorString,ErrStrLen)))
01192                 {
01193                     return -1;
01194                 }
01195             }
01196             else if(!strcmp(ALLOW_PROXY, pcToken))
01197             {
01198                 ServerConf->allow_proxy = 1;
01199             }
01200             else if(!strcmp(FLOW_DEPTH, pcToken))
01201             {
01202                 if((iRet = ProcessFlowDepth(ServerConf, 
01203                                             ErrorString, ErrStrLen)))
01204                 {
01205                     return iRet;
01206                 }
01207             }
01208             else if(!strcmp(GLOBAL_ALERT, pcToken))
01209             {
01210                 ServerConf->no_alerts = 1;
01211             }
01212             else if(!strcmp(OVERSIZE_DIR, pcToken))
01213             {
01214                 if((iRet = ProcessOversizeDir(ServerConf, 
01215                                               ErrorString, ErrStrLen)))
01216                 {
01217                     return iRet;
01218                 }
01219  
01220             }
01221             else if(!strcmp(INSPECT_URI_ONLY, pcToken))
01222             {
01223                 ServerConf->uri_only = 1;
01224             }
01225             else
01226             {
01227                 snprintf(ErrorString, ErrStrLen,
01228                          "Invalid token while configuring the profile token.  "
01229                          "The only allowed tokens when configuring profiles "
01230                          "are: '%s', '%s', '%s', '%s', '%s', '%s', and '%s'.",
01231                          PORTS,IIS_UNICODE_MAP, ALLOW_PROXY, FLOW_DEPTH,
01232                          GLOBAL_ALERT, OVERSIZE_DIR, INSPECT_URI_ONLY);
01233 
01234                 return -1;
01235             }
01236 
01237         } while((pcToken = strtok(NULL, CONF_SEPARATORS)));
01238 
01239         if(!iPorts)
01240         {
01241             snprintf(ErrorString, ErrStrLen,
01242                      "No port list to the profile token.");
01243 
01244             return -1;
01245         }
01246 
01247         return 0;
01248     }
01249 
01250     /*
01251     **  If there is no profile configuration then we go into the hard-core
01252     **  configuration.
01253     */
01254     do
01255     {
01256         if(!strcmp(PORTS, pcToken))
01257         {
01258             if((iRet = ProcessPorts(ServerConf, 
01259                                     ErrorString, ErrStrLen)))
01260             {
01261                 return iRet;
01262             }
01263         }
01264         else if(!strcmp(FLOW_DEPTH, pcToken))
01265         {
01266             if((iRet = ProcessFlowDepth(ServerConf, 
01267                                         ErrorString, ErrStrLen)))
01268             {
01269                 return iRet;
01270             }
01271         }
01272         else if(!strcmp(IIS_UNICODE_MAP, pcToken))
01273         {
01274             if((iRet = ProcessIISUnicodeMap(&ServerConf->iis_unicode_map,
01275                                          &ServerConf->iis_unicode_map_filename,
01276                                             &ServerConf->iis_unicode_codepage,
01277                                             ErrorString, ErrStrLen)))
01278             {
01279                 return iRet;
01280             }
01281         }
01282         else if(!strcmp(CHUNK_LENGTH, pcToken))
01283         {
01284             if((iRet = ProcessChunkLength(ServerConf,ErrorString,ErrStrLen )))
01285             {
01286                 return iRet;
01287             }
01288         }
01289         else if(!strcmp(PIPELINE, pcToken))
01290         {
01291             ServerConf->no_pipeline = 1;
01292         }
01293         else if(!strcmp(NON_STRICT, pcToken))
01294         {
01295             ServerConf->non_strict = 1;
01296         }
01297         else if(!strcmp(ALLOW_PROXY, pcToken))
01298         {
01299             ServerConf->allow_proxy = 1;
01300         }
01301         else if(!strcmp(GLOBAL_ALERT, pcToken))
01302         {
01303             ServerConf->no_alerts = 1;
01304         }
01305         else if(!strcmp(TAB_URI_DELIMITER, pcToken))
01306         {
01307             ServerConf->tab_uri_delimiter = 1;
01308         }        
01309         else if(!strcmp(OVERSIZE_DIR, pcToken))
01310         {
01311             if((iRet = ProcessOversizeDir(ServerConf, 
01312                                           ErrorString, ErrStrLen)))
01313             {
01314                 return iRet;
01315             }
01316  
01317         }
01318         else if(!strcmp(INSPECT_URI_ONLY, pcToken))
01319         {
01320             ServerConf->uri_only = 1;
01321         }
01322 
01323         /*
01324         **  Start the CONF_OPT configurations.
01325         */
01326         else if(!strcmp(ASCII, pcToken))
01327         {
01328             ConfOpt = &ServerConf->ascii;
01329             if((iRet = ProcessConfOpt(ConfOpt, ASCII, 
01330                                       ErrorString, ErrStrLen)))
01331             {
01332                 return iRet;
01333             }
01334         }
01335         else if(!strcmp(UTF_8, pcToken))
01336         {
01337             /*
01338             **  In order for this to work we also need to set ASCII
01339             */
01340             ServerConf->ascii.on    = 1;
01341 
01342             ConfOpt = &ServerConf->utf_8;
01343             if((iRet = ProcessConfOpt(ConfOpt, UTF_8,
01344                                       ErrorString, ErrStrLen)))
01345             {
01346                 return iRet;
01347             }
01348         }
01349         else if(!strcmp(IIS_UNICODE, pcToken))
01350         {
01351             if(ServerConf->iis_unicode_map == NULL)
01352             {
01353                 ServerConf->iis_unicode_map = GlobalConf->iis_unicode_map;
01354             }
01355 
01356             /*
01357             **  We need to set up:
01358             **    - ASCII
01359             **    - DOUBLE_DECODE
01360             **    - U_ENCODE
01361             **    - BARE_BYTE
01362             **    - IIS_UNICODE
01363             **    - BASE36
01364             */
01365             ServerConf->ascii.on           = 1;
01366 
01367             ConfOpt = &ServerConf->iis_unicode;
01368             if((iRet = ProcessConfOpt(ConfOpt, IIS_UNICODE,
01369                                       ErrorString, ErrStrLen)))
01370             {
01371                 return iRet;
01372             }
01373         }
01374         else if(!strcmp(DOUBLE_DECODE, pcToken))
01375         {
01376             ServerConf->ascii.on             = 1;
01377 
01378             ConfOpt = &ServerConf->double_decoding;
01379             if((iRet = ProcessConfOpt(ConfOpt, DOUBLE_DECODE,
01380                                       ErrorString, ErrStrLen)))
01381             {
01382                 return iRet;
01383             }
01384         }
01385         else if(!strcmp(U_ENCODE, pcToken))
01386         {
01387             /*
01388             **  With %U encoding, we don't want base36 on.
01389             */
01390             ServerConf->base36.on = 0;
01391             ServerConf->base36.alert = 0;
01392 
01393             /*
01394             **  We set the unicode map to default if it's not already
01395             **  set.
01396             */
01397             if(ServerConf->iis_unicode_map == NULL)
01398             {
01399                 ServerConf->iis_unicode_map = GlobalConf->iis_unicode_map;
01400             }
01401 
01402             ConfOpt = &ServerConf->u_encoding;
01403             if((iRet = ProcessConfOpt(ConfOpt, U_ENCODE,
01404                                       ErrorString, ErrStrLen)))
01405             {
01406                 return iRet;
01407             }
01408         }
01409         else if(!strcmp(BARE_BYTE, pcToken))
01410         {
01411             ConfOpt = &ServerConf->bare_byte;
01412             if((iRet = ProcessConfOpt(ConfOpt, BARE_BYTE,
01413                                       ErrorString, ErrStrLen)))
01414             {
01415                 return iRet;
01416             }
01417         }
01418         else if(!strcmp(BASE36, pcToken))
01419         {
01420             ServerConf->ascii.on      = 1;
01421 
01422             /*
01423             **  With Base36 encoding, we don't want to have %U encoding
01424             **  turned on.
01425             */
01426             ServerConf->u_encoding.on    = 0;
01427             ServerConf->u_encoding.alert = 0;
01428 
01429             ConfOpt = &ServerConf->base36;
01430             if((iRet = ProcessConfOpt(ConfOpt, BASE36,
01431                                       ErrorString, ErrStrLen)))
01432             {
01433                 return iRet;
01434             }
01435         }
01436         else if(!strcmp(NON_RFC_CHAR, pcToken))
01437         {
01438             if((iRet = ProcessNonRfcChar(ServerConf, ErrorString, ErrStrLen)))
01439             {
01440                 return iRet;
01441             }
01442         }
01443         else if(!strcmp(MULTI_SLASH, pcToken))
01444         {
01445             ConfOpt = &ServerConf->multiple_slash;
01446             if((iRet = ProcessConfOpt(ConfOpt, MULTI_SLASH,
01447                                       ErrorString, ErrStrLen)))
01448             {
01449                 return iRet;
01450             }
01451         }
01452         else if(!strcmp(IIS_BACKSLASH, pcToken))
01453         {
01454             ConfOpt = &ServerConf->iis_backslash;
01455             if((iRet = ProcessConfOpt(ConfOpt, IIS_BACKSLASH,
01456                                       ErrorString, ErrStrLen)))
01457             {
01458                 return iRet;
01459             }
01460         }
01461         else if(!strcmp(DIRECTORY, pcToken))
01462         {
01463             ConfOpt = &ServerConf->directory;
01464             if((iRet = ProcessConfOpt(ConfOpt, DIRECTORY,
01465                                       ErrorString, ErrStrLen)))
01466             {
01467                 return iRet;
01468             }
01469         }
01470         else if(!strcmp(APACHE_WS, pcToken))
01471         {
01472             ConfOpt = &ServerConf->apache_whitespace;
01473             if((iRet = ProcessConfOpt(ConfOpt, APACHE_WS,
01474                                       ErrorString, ErrStrLen)))
01475             {
01476                 return iRet;
01477             }
01478         }
01479         else if(!strcmp(IIS_DELIMITER, pcToken))
01480         {
01481             ConfOpt = &ServerConf->iis_delimiter;
01482             if((iRet = ProcessConfOpt(ConfOpt, IIS_DELIMITER,
01483                                       ErrorString, ErrStrLen)))
01484             {
01485                 return iRet;
01486             }
01487         }
01488         else if(!strcmp(WEBROOT, pcToken))
01489         {
01490             ConfOpt = &ServerConf->webroot;
01491             if((iRet = ProcessConfOpt(ConfOpt, WEBROOT,
01492                                       ErrorString, ErrStrLen)))
01493             {
01494                 return iRet;
01495             }
01496         }
01497         else
01498         {
01499             snprintf(ErrorString, ErrStrLen,
01500                     "Invalid keyword '%s' for server configuration.",
01501                      pcToken);
01502 
01503             return -1;
01504         }
01505     } 
01506     while((pcToken = strtok(NULL, CONF_SEPARATORS)));
01507         
01508     return 0;
01509 }
01510 
01511 static int PrintConfOpt(HTTPINSPECT_CONF_OPT *ConfOpt, char *Option)
01512 {
01513     if(!ConfOpt || !Option)
01514     {
01515         return HI_INVALID_ARG;
01516     }
01517 
01518     if(ConfOpt->on)
01519     {
01520         LogMessage("      %s: YES alert: %s\n", Option,
01521                ConfOpt->alert ? "YES" : "NO");
01522     }
01523     else
01524     {
01525         LogMessage("      %s: OFF\n", Option);
01526     }
01527 
01528     return 0;
01529 }
01530 
01531 static int PrintServerConf(HTTPINSPECT_CONF *ServerConf)
01532 {
01533     char buf[STD_BUF+1];
01534     int iCtr;
01535     int iNonRfcChar = 0;
01536 
01537     if(!ServerConf)
01538     {
01539         return HI_INVALID_ARG;
01540     }
01541 
01542     memset(buf, 0, STD_BUF+1);
01543     snprintf(buf, STD_BUF, "      Ports: ");
01544 
01545     /*
01546     **  Print out all the applicable ports.
01547     */
01548     for(iCtr = 0; iCtr < 65536; iCtr++)
01549     {
01550         if(ServerConf->ports[iCtr])
01551         {
01552             sfsnprintfappend(buf, STD_BUF, "%d ", iCtr);
01553         }
01554     }
01555 
01556     LogMessage("%s\n", buf);
01557 
01558     LogMessage("      Flow Depth: %d\n", ServerConf->flow_depth);
01559     LogMessage("      Max Chunk Length: %d\n", ServerConf->chunk_length);
01560     LogMessage("      Inspect Pipeline Requests: %s\n",
01561                ServerConf->no_pipeline ? "NO" : "YES");
01562     LogMessage("      URI Discovery Strict Mode: %s\n",
01563                ServerConf->non_strict ? "NO" : "YES");
01564     LogMessage("      Allow Proxy Usage: %s\n",
01565                ServerConf->allow_proxy ? "YES" : "NO");
01566     LogMessage("      Disable Alerting: %s\n", 
01567                ServerConf->no_alerts ? "YES":"NO");
01568     LogMessage("      Oversize Dir Length: %d\n",
01569                ServerConf->long_dir);
01570     LogMessage("      Only inspect URI: %s\n",
01571                ServerConf->uri_only ? "YES" : "NO");
01572 
01573     PrintConfOpt(&ServerConf->ascii, "Ascii");
01574     PrintConfOpt(&ServerConf->double_decoding, "Double Decoding");
01575     PrintConfOpt(&ServerConf->u_encoding, "%U Encoding");
01576     PrintConfOpt(&ServerConf->bare_byte, "Bare Byte");
01577     PrintConfOpt(&ServerConf->base36, "Base36");
01578     PrintConfOpt(&ServerConf->utf_8, "UTF 8");
01579     PrintConfOpt(&ServerConf->iis_unicode, "IIS Unicode");
01580     PrintConfOpt(&ServerConf->multiple_slash, "Multiple Slash");
01581     PrintConfOpt(&ServerConf->iis_backslash, "IIS Backslash");
01582     PrintConfOpt(&ServerConf->directory, "Directory Traversal");
01583     PrintConfOpt(&ServerConf->webroot, "Web Root Traversal");
01584     PrintConfOpt(&ServerConf->apache_whitespace, "Apache WhiteSpace");
01585     PrintConfOpt(&ServerConf->iis_delimiter, "IIS Delimiter");
01586 
01587     if(ServerConf->iis_unicode_map_filename)
01588     {
01589         LogMessage("      IIS Unicode Map Filename: %s\n",
01590                    ServerConf->iis_unicode_map_filename);
01591         LogMessage("      IIS Unicode Map Codepage: %d\n",
01592                    ServerConf->iis_unicode_codepage);
01593     }
01594     else if(ServerConf->iis_unicode_map)
01595     {
01596         LogMessage("      IIS Unicode Map: "                                    
01597                    "GLOBAL IIS UNICODE MAP CONFIG\n");
01598     }
01599     else
01600     {
01601         LogMessage("      IIS Unicode Map:  NOT CONFIGURED\n");
01602     }
01603 
01604     /*
01605     **  Print out the non-rfc chars
01606     */
01607     memset(buf, 0, STD_BUF+1);
01608     snprintf(buf, STD_BUF, "      Non-RFC Compliant Characters: ");
01609     for(iCtr = 0; iCtr < 256; iCtr++)
01610     {
01611         if(ServerConf->non_rfc_chars[iCtr])
01612         {
01613             sfsnprintfappend(buf, STD_BUF, "0x%.2x ", (u_char)iCtr);
01614             iNonRfcChar = 1;
01615         }
01616     }
01617 
01618     if(!iNonRfcChar)
01619     {
01620         sfsnprintfappend(buf, STD_BUF, "NONE");
01621     }
01622 
01623     LogMessage("%s\n", buf);
01624 
01625     return 0;
01626 }
01627 
01628 static int ProcessUniqueServerConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf,
01629                              char *ErrorString, int ErrStrLen)
01630 {
01631     char *pcToken;
01632     unsigned long Ip;
01633     struct in_addr ip_addr;
01634     HTTPINSPECT_CONF *ServerConf;
01635     static int s_iDefaultServer = 0;
01636     int iRet;
01637 
01638     pcToken = strtok(NULL, CONF_SEPARATORS);
01639     if(!pcToken)
01640     {
01641         snprintf(ErrorString, ErrStrLen,
01642                 "No arguments to '%s' token.", SERVER);
01643 
01644         return -1;
01645     }
01646 
01647     /*
01648     **  Check for the default configuration first
01649     */
01650     if(!strcmp(SERVER_DEFAULT, pcToken))
01651     {
01652         if(s_iDefaultServer)
01653         {
01654             snprintf(ErrorString, ErrStrLen,
01655                     "Cannot configure '%s' settings more than once.",
01656                     GLOBAL_SERVER);
01657 
01658             return -1;
01659         }
01660 
01661         s_iDefaultServer = 1;
01662 
01663         ServerConf = &GlobalConf->global_server;
01664 
01665         /*
01666         **  Reset the global server configuration
01667         */
01668         if(hi_ui_config_reset_server(ServerConf))
01669         {
01670             snprintf(ErrorString, ErrStrLen,
01671                     "Cannot reset the HttpInspect default server configuration.");
01672 
01673             return -1;
01674         }
01675 
01676         if((iRet = ProcessServerConf(GlobalConf, ServerConf, 
01677                                      ErrorString, ErrStrLen)))
01678         {
01679             return iRet;
01680         }
01681 
01682         /*
01683         **  Start writing out the Default Server Config
01684         */
01685         LogMessage("    DEFAULT SERVER CONFIG:\n");
01686     }
01687     else
01688     {
01689         /*
01690         **  Convert string to IP address
01691         */
01692         Ip = inet_addr(pcToken);
01693         if(Ip == INADDR_NONE)
01694         {
01695             snprintf(ErrorString, ErrStrLen,
01696                     "Invalid IP to '%s' token.", SERVER);
01697 
01698             return -1;
01699         }
01700 
01701         /*
01702         **  allocate the memory for the server configuration
01703         */
01704         ServerConf = malloc(sizeof(HTTPINSPECT_CONF));
01705         if(!ServerConf)
01706         {
01707             snprintf(ErrorString, ErrStrLen,
01708                     "Could not allocate memory for server configuration.");
01709 
01710             return -1;
01711         }
01712 
01713         memset(ServerConf, 0x00, sizeof(HTTPINSPECT_CONF));
01714 
01715         if((iRet = ProcessServerConf(GlobalConf, ServerConf, 
01716                                      ErrorString, ErrStrLen)))
01717         {
01718             return iRet;
01719         }
01720 
01721         if((iRet = hi_ui_config_add_server(GlobalConf, Ip, ServerConf)))
01722         {
01723             /*
01724             **  Check for already added servers
01725             */
01726             if(iRet == HI_NONFATAL_ERR)
01727             {
01728                 snprintf(ErrorString, ErrStrLen,
01729                         "Duplicate server configuration.");
01730 
01731                 return -1;
01732             }
01733             else
01734             {
01735                 snprintf(ErrorString, ErrStrLen,
01736                         "Error when adding server configuration.");
01737 
01738                 return -1;
01739             }
01740         }
01741 
01742         ip_addr.s_addr = Ip;
01743 
01744         /*
01745         **  Print out the configuration header
01746         */
01747         LogMessage("    SERVER: %s\n", inet_ntoa(ip_addr));
01748     }
01749 
01750     /*
01751     **  Finish printing out the server configuration
01752     */
01753     PrintServerConf(ServerConf);
01754 
01755     return 0;
01756 }
01757 
01758 static int PrintGlobalConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf)
01759 {
01760     LogMessage("HttpInspect Config:\n");
01761 
01762     LogMessage("    GLOBAL CONFIG\n");
01763     LogMessage("      Max Pipeline Requests:    %d\n", 
01764                GlobalConf->max_pipeline_requests);
01765     LogMessage("      Inspection Type:          %s\n",
01766                GlobalConf->inspection_type ? "STATEFUL" : "STATELESS");
01767     LogMessage("      Detect Proxy Usage:       %s\n",
01768                GlobalConf->proxy_alert ? "YES" : "NO");
01769     LogMessage("      IIS Unicode Map Filename: %s\n",
01770                GlobalConf->iis_unicode_map_filename);
01771     LogMessage("      IIS Unicode Map Codepage: %d\n",
01772                GlobalConf->iis_unicode_codepage);
01773 
01774     return 0;
01775 }
01776 
01777 
01778 
01779 /*
01780 **  NAME
01781 **    HttpInspectSnortConf::
01782 */
01783 /**
01784 **  This function takes the HttpInspect configuration line from the 
01785 **  snort.conf and creats an HttpInspect configuration.
01786 **
01787 **  This routine takes care of the snort specific configuration processing
01788 **  and calls the generic routines to add specific server configurations.
01789 **  It sets the configuration structure elements in this routine.
01790 **
01791 **  The ErrorString is passed in as a pointer, and the ErrStrLen tells
01792 **  us the length of the pointer.
01793 **
01794 **  @param GlobalConf  a pointer to the global configuration.
01795 **  @param args        a pointer to argument string.
01796 **  @param iGlobal     whether this is the global configuration or a server
01797 **  @param ErrorString a pointer for an error string.
01798 **  @param ErrStrLen   the length of the error string.
01799 **
01800 **  @return an error code integer 
01801 **          (0 = success, >0 = non-fatal error, <0 = fatal error)
01802 **
01803 **  @retval  0 success
01804 **  @retval  1 generic non-fatal error
01805 **  @retval -1 generic fatal error
01806 **  @retval -2 ErrorString is undefined
01807 */
01808 int HttpInspectSnortConf(HTTPINSPECT_GLOBAL_CONF *GlobalConf, char *args, int iGlobal,
01809                          char *ErrorString, int ErrStrLen)
01810 {
01811     char        *pcToken;
01812     static int  s_iGlobal = 0;
01813     int         iRet;
01814 
01815     /*
01816     **  Check input variables
01817     */
01818     if(ErrorString == NULL)
01819     {
01820         return -2;
01821     }
01822     
01823     if(GlobalConf == NULL)
01824     {
01825         snprintf(ErrorString, ErrStrLen, 
01826                 "Global configuration variable undefined.");
01827 
01828         return -1;
01829     }
01830 
01831     if(args == NULL)
01832     {
01833         snprintf(ErrorString, ErrStrLen, 
01834                 "No arguments to HttpInspect configuration.");
01835 
01836         return -1;
01837     }
01838 
01839     /*
01840     **  Find out what is getting configured
01841     */
01842     pcToken = strtok(args, CONF_SEPARATORS);
01843     if(pcToken == NULL)
01844     {
01845         snprintf(ErrorString, ErrStrLen, 
01846                 "No arguments to HttpInspect configuration.");
01847 
01848         return -1;
01849     }
01850 
01851     /*
01852     **  Global Configuration Processing
01853     **  We only process the global configuration once, but always check for
01854     **  user mistakes, like configuring more than once.  That's why we
01855     **  still check for the global token even if it's been checked.
01856     */
01857     if((s_iGlobal || iGlobal) && !strcmp(pcToken, GLOBAL)) 
01858     {
01859         /*
01860         **  Don't allow user to configure twice
01861         */
01862         if(s_iGlobal)
01863         {
01864             snprintf(ErrorString, ErrStrLen,
01865                     "Cannot configure '%s' settings more than once.",
01866                     GLOBAL);
01867 
01868             return -1;
01869         }
01870 
01871         /*
01872         **  Reset the Global configuration
01873         */
01874         if(hi_ui_config_reset_global(GlobalConf))
01875         {
01876             snprintf(ErrorString, ErrStrLen,
01877                     "Cannot reset the HttpInspect global configuration.");
01878 
01879             return -1;
01880         }
01881 
01882         /*
01883         **  Reset the global server, so if there isn't one specified, we
01884         **  honor that.
01885         */
01886         if(hi_ui_config_reset_server(&GlobalConf->global_server))
01887         {
01888             snprintf(ErrorString, ErrStrLen,
01889                     "Cannot reset the HttpInspect default server configuration.");
01890 
01891             return -1;
01892         }
01893 
01894         if((iRet = ProcessGlobalConf(GlobalConf, ErrorString, ErrStrLen)))
01895         {
01896             return iRet;
01897         }
01898 
01899         s_iGlobal = 1;
01900 
01901         /*
01902         **  Let's print out the global config
01903         */
01904         PrintGlobalConf(GlobalConf);
01905     }
01906     /*
01907     **  Server Configuration
01908     */
01909     else if(!iGlobal && !strcmp(pcToken, SERVER))
01910     {
01911         if((iRet = ProcessUniqueServerConf(GlobalConf, 
01912                                            ErrorString, ErrStrLen)))
01913         {
01914             return iRet;
01915         }
01916     }
01917     /*
01918     **  Invalid configuration keyword
01919     */
01920     else
01921     {
01922         if(iGlobal)
01923         {
01924             snprintf(ErrorString, ErrStrLen,
01925                     "Invalid configuration token '%s'.  " 
01926                     "The first configuration must start with a '%s' "
01927                     "configuration type.", pcToken, GLOBAL);
01928         }
01929         else
01930         {
01931             snprintf(ErrorString, ErrStrLen,
01932                     "Invalid configuration token '%s'.  Must be a '%s' "
01933                     "configuration.", pcToken, SERVER);
01934         }
01935 
01936         return -1;
01937     }
01938 
01939     return 0;
01940 }
01941 
01942 /*
01943 **  NAME
01944 **    LogEvents::
01945 */
01946 /**
01947 **  This is the routine that logs HttpInspect alerts through Snort.
01948 **  
01949 **  Every Session gets looked at for any logged events, and if there are
01950 **  events to be logged then we select the one with the highest priority.
01951 **  
01952 **  We use a generic event structure that we set for each different event
01953 **  structure.  This way we can use the same code for event logging regardless
01954 **  of what type of event strucure we are dealing with.
01955 **  
01956 **  The important things to know about this function is how to work with
01957 **  the event queue.  The number of unique events is contained in the
01958 **  stack_count variable.  So we loop through all the unique events and
01959 **  find which one has the highest priority.  During this loop, we also
01960 **  re-initialize the individual event counts for the next iteration, saving
01961 **  us time in a separate initialization phase.
01962 **  
01963 **  After we've iterated through all the events and found the one with the
01964 **  highest priority, we then log that event through snort.
01965 **  
01966 **  We've mapped the HttpInspect and the Snort alert IDs together, so we
01967 **  can access them directly instead of having a more complex mapping
01968 **  function.  It's the only good way to do this.
01969 **  
01970 **  @param Session          pointer to Session construct
01971 **  @param p                pointer to the Snort packet construct
01972 **  @param iInspectMode     inspection mode to take event queue from
01973 **  
01974 **  @return integer
01975 **  
01976 **  @retval 0 this function only return success
01977 */
01978 static inline int LogEvents(HI_SESSION *hi_ssn, Packet *p, int iInspectMode)
01979 {
01980     HI_GEN_EVENTS GenEvents;
01981     HI_EVENT      *OrigEvent;
01982     HI_EVENT      *HiEvent = NULL;
01983     Session       *ssn = NULL;
01984     u_int32_t     uiMask = 0;
01985     int           iGenerator;
01986     int           iStackCnt;
01987     int           iEvent;
01988     int           iCtr;
01989 
01990     /*
01991     **  Set the session ptr, if applicable
01992     */
01993     if(p && p->ssnptr)
01994         ssn = (Session *)p->ssnptr;
01995     
01996     if(iInspectMode == HI_SI_CLIENT_MODE)
01997     {
01998         GenEvents.stack =       hi_ssn->client.event_list.stack;
01999         GenEvents.stack_count = &(hi_ssn->client.event_list.stack_count);
02000         GenEvents.events =      hi_ssn->client.event_list.events;
02001 
02002         iGenerator = GENERATOR_SPP_HTTP_INSPECT_CLIENT;
02003     }
02004     else if(iInspectMode == HI_SI_SERVER_MODE)
02005     {
02006         /*
02007         **  We have no server events right now, so we just return.
02008         */
02009         return 0;
02010     }
02011     else
02012     {
02013         GenEvents.stack =       hi_ssn->anom_server.event_list.stack;
02014         GenEvents.stack_count = &(hi_ssn->anom_server.event_list.stack_count);
02015         GenEvents.events =      hi_ssn->anom_server.event_list.events;
02016 
02017         iGenerator = GENERATOR_SPP_HTTP_INSPECT_ANOM_SERVER;
02018     }
02019 
02020     /*
02021     **  Now starts the generic event processing
02022     */
02023     iStackCnt = *(GenEvents.stack_count);
02024 
02025     /*
02026     **  IMPORTANT::
02027     **  We have to check the stack count of the event queue before we process
02028     **  an log.
02029     */
02030     if(iStackCnt == 0)
02031     {
02032         return 0;
02033     }
02034 
02035     /*
02036     **  Cycle through the events and select the event with the highest
02037     **  priority.
02038     */
02039     for(iCtr = 0; iCtr < iStackCnt; iCtr++)
02040     {
02041         iEvent = GenEvents.stack[iCtr];
02042         OrigEvent = &(GenEvents.events[iEvent]);
02043 
02044         /*
02045         **  Set the event to start off the comparison
02046         */
02047         if(!HiEvent)
02048         {
02049             HiEvent = OrigEvent;
02050         }
02051 
02052         /*
02053         **  This is our "comparison function".  Log the event with the highest
02054         **  priority.
02055         */
02056         if(OrigEvent->event_info->priority < HiEvent->event_info->priority)
02057         {
02058             HiEvent = OrigEvent;
02059         }
02060 
02061         /*
02062         **  IMPORTANT:
02063         **    This is how we reset the events in the event queue.
02064         **    If you miss this step, you can be really screwed.
02065         */
02066         OrigEvent->count = 0;
02067     }
02068 
02069     /*
02070     **  We use the iEvent+1 because the event IDs between snort and
02071     **  HttpInspect are mapped off-by-one.  Don't ask why, drink Bud
02072     **  Dry . . . They're mapped off-by one because in the internal
02073     **  HttpInspect queue, events are mapped starting at 0.  For some
02074     **  reason, it appears that the first event can't be zero, so we
02075     **  use the internal value and add one for snort.
02076     */
02077     iEvent = HiEvent->event_info->alert_id + 1;
02078 
02079     uiMask = (u_int32_t)(1 << (iEvent & 31));
02080 
02081     /*
02082     **  If we've already logged this event for this stream, then
02083     **  don't log it again.
02084     */
02085     if(ssn && (ssn->http_alert_flags & uiMask))
02086     {
02087         return 0;
02088     }
02089 
02090     SnortEventqAdd(iGenerator, iEvent, 1, 0, 3, HiEvent->event_info->alert_str,0);
02091 
02092     /*
02093     **  Set the http_flag bit so we don't log the event on a reassembled
02094     **  stream.
02095     */
02096     if(ssn)
02097         ssn->http_alert_flags |= uiMask;
02098 
02099     /*
02100     **  Reset the event queue stack counter, in the case of pipelined
02101     **  requests.
02102     */
02103     *(GenEvents.stack_count) = 0;
02104 
02105     return 0;
02106 }
02107 
02108 static inline int SetSiInput(HI_SI_INPUT *SiInput, Packet *p)
02109 {
02110     Session *ssnptr = NULL;
02111 
02112     SiInput->sip   = p->iph->ip_src.s_addr;
02113     SiInput->dip   = p->iph->ip_dst.s_addr;
02114     SiInput->sport = p->sp;
02115     SiInput->dport = p->dp;
02116 
02117     if(p->ssnptr)
02118     {
02119         ssnptr = (Session *)p->ssnptr;
02120     }
02121 
02122     /*
02123     **  We now set the packet direction
02124     */
02125     if(ssnptr && ssnptr->session_flags & SSNFLAG_MIDSTREAM)
02126     {
02127         SiInput->pdir = HI_SI_NO_MODE;
02128     }
02129     else if(p->packet_flags & PKT_FROM_SERVER)
02130     {
02131         SiInput->pdir = HI_SI_SERVER_MODE;
02132     }
02133     else if(p->packet_flags & PKT_FROM_CLIENT)
02134     {
02135         SiInput->pdir = HI_SI_CLIENT_MODE;
02136     }
02137     else
02138     {
02139         SiInput->pdir = HI_SI_NO_MODE;
02140     }
02141 
02142     return HI_SUCCESS;
02143 
02144 }
02145 
02146 /*
02147 **  NAME
02148 **    SnortHttpInspect::
02149 */
02150 /**
02151 **  This function calls the HttpInspect function that processes an HTTP 
02152 **  session.
02153 **
02154 **  We need to instantiate a pointer for the HI_SESSION that HttpInspect 
02155 **  fills in.  Right now stateless processing fills in this session, which 
02156 **  we then normalize, and eventually detect.  We'll have to handle 
02157 **  separately the normalization events, etc.
02158 **  
02159 **  This function is where we can see from the highest level what the
02160 **  HttpInspect flow looks like.
02161 **
02162 **  @param GlobalConf pointer to the global configuration
02163 **  @param p          pointer to the Packet structure
02164 **
02165 **  @return integer
02166 **
02167 **  @retval  0 function successful
02168 **  @retval <0 fatal error
02169 **  @retval >0 non-fatal error
02170 */
02171 int SnortHttpInspect(HTTPINSPECT_GLOBAL_CONF *GlobalConf, Packet *p)
02172 {
02173     extern HttpUri UriBufs[URI_COUNT];
02174     extern int     do_detect;
02175     extern OptTreeNode *otn_tmp;
02176 
02177     HI_SESSION  *Session;
02178     HI_SI_INPUT SiInput;
02179     int iInspectMode = 0;
02180     int iRet;
02181     int iCallDetect = 1;
02182     
02183     if(!p->iph || !p->tcph)
02184     {
02185         return 1;
02186     }
02187 
02188     /*
02189     **  Set up the HI_SI_INPUT pointer.  This is what the session_inspection()
02190     **  routines use to determine client and server traffic.  Plus, this makes
02191     **  the HttpInspect library very independent from snort.
02192     */
02193     SetSiInput(&SiInput, p);
02194 
02195     /*
02196     **  HTTPINSPECT PACKET FLOW::
02197     **
02198     **  Session Inspection Module::
02199     **    The Session Inspection Module retrieves the appropriate server
02200     **    configuration for sessions, and takes care of the stateless
02201     **    vs. stateful processing in order to do this.  Once this module
02202     **    does it's magic, we're ready for the primetime.
02203     **
02204     **  HTTP Inspection Module::
02205     **    This isn't really a module in HttpInspect, but more of a helper
02206     **    function that sends the data to the appropriate inspection
02207     **    routine (client, server, anomalous server detection).
02208     **
02209     **  HTTP Normalization Module::
02210     **    This is where we normalize the data from the HTTP Inspection
02211     **    Module.  The Normalization module handles what type of normalization
02212     **    to do (client, server).
02213     **
02214     **  HTTP Detection Module::
02215     **    This isn't being used in the first iteration of HttpInspect, but
02216     **    all the HTTP detection components of signatures will be.
02217     **
02218     **  HTTP Event Output Module::
02219     **    The Event Ouput Module handles any events that have been logged
02220     **    in the inspection, normalization, or detection phases.
02221     */ 
02222     
02223     /*
02224     **  Session Inspection Module::
02225     */
02226     if((iRet = hi_si_session_inspection(GlobalConf, &Session, &SiInput, 
02227                     &iInspectMode)))
02228     {
02229         return iRet;
02230     }
02231     
02232     /*
02233     **  HTTP Inspection Module::
02234     **
02235     **  This is where we do the client/server inspection and find the
02236     **  various HTTP protocol fields.  We then normalize these fields and
02237     **  call the detection engine.
02238     **
02239     **  The reason for the loop is for pipelined requests.  Doing pipelined
02240     **  requests in this way doesn't require any memory or tracking overhead.
02241     **  Instead, we just process each request linearly.
02242     */
02243     do
02244     {
02245         /*
02246         **  INIT:
02247         **  We set this equal to zero (again) because of the pipelining
02248         **  requests.  We don't want to bail before we get to setting the
02249         **  URI, so we make sure here that this can't happen.
02250         */
02251         p->uri_count = 0;
02252         UriBufs[0].decode_flags = 0;
02253 
02254         if(iInspectMode == HI_SI_SERVER_MODE)
02255         {
02256             /* Don't do server inspection */
02257             if (Session->server_conf->flow_depth == -1)
02258             {
02259                 do_detect = 0;
02260                 p->preprocessors = 0;
02261 
02262                 p->preprocessors |= PP_PORTSCAN;
02263                 p->preprocessors |= PP_STREAM4;
02264 
02265                 return 0;
02266             }
02267         }
02268 
02269         if((iRet = hi_mi_mode_inspection(Session, iInspectMode, p->data,
02270                                          p->dsize)))
02271         {
02272             LogEvents(Session,p,iInspectMode);
02273             return iRet;
02274         }
02275 
02276         if((iRet = hi_normalization(Session, iInspectMode)))
02277         {
02278             LogEvents(Session,p,iInspectMode);
02279             return iRet;
02280         }
02281 
02282         /*
02283         **  Let's setup the pointers for the detection engine, and
02284         **  then go for it.
02285         */
02286         if(iInspectMode == HI_SI_CLIENT_MODE)
02287         {
02288             if(!iCallDetect || Session->server_conf->uri_only)
02289             {
02290                 UriBufs[0].decode_flags |= HTTPURI_PIPELINE_REQ;
02291             }
02292 
02293             if(Session->client.request.uri_norm)
02294             {
02295                 UriBufs[0].uri    = Session->client.request.uri_norm;
02296                 UriBufs[0].length = Session->client.request.uri_norm_size;
02297                 p->uri_count = 1;
02298                 p->packet_flags |= PKT_HTTP_DECODE;
02299             }
02300             else if(Session->client.request.uri)
02301             {
02302                 UriBufs[0].uri    = Session->client.request.uri;
02303                 UriBufs[0].length = Session->client.request.uri_size;
02304                 p->uri_count = 1;
02305 
02306                 p->packet_flags |= PKT_HTTP_DECODE;
02307             }
02308         }
02309         else if(iInspectMode == HI_SI_SERVER_MODE)
02310         {
02311             /*
02312             **  We set the header length and detect the normal way.
02313             */
02314             p->dsize = Session->server.header_size;
02315 
02316             /*
02317             **  If dsize is 0, we only get here because dsize was set to 0
02318             **  by the server module by the flow_depth inspection.
02319             **
02320             **  We check here to see whether this was a server response
02321             **  header or not.  If the dsize is 0 then, we know that this
02322             **  is not the header and don't do any detection.
02323             */
02324             if(p->dsize == 0)
02325             {
02326                 do_detect = 0;
02327                 p->preprocessors = 0;
02328 
02329                 p->preprocessors |= PP_PORTSCAN;
02330                 p->preprocessors |= PP_STREAM4;
02331 
02332                 return 0;
02333             }
02334         }
02335         else
02336         {
02337             /*
02338             **  We log events before doing detection because every non-HTTP
02339             **  packet is possible an anomalous server.  So we still want to
02340             **  go through the regular detection engine, and just log any
02341             **  alerts here before returning. 
02342             **
02343             **  Return normally if this isn't either HTTP client or server
02344             **  traffic.
02345             */
02346             if(Session->anom_server.event_list.stack_count)
02347                 LogEvents(Session, p, iInspectMode);
02348 
02349             return 0;
02350         }
02351 
02352         /*
02353         **  If we get here we either had a client or server request/response.
02354         **  We do the detection here, because we're starting a new paradigm
02355         **  about protocol decoders.
02356         **
02357         **  Protocol decoders are now their own detection engine, since we are
02358         **  going to be moving protocol field detection from the generic
02359         **  detection engine into the protocol module.  This idea scales much
02360         **  better than having all these Packet struct field checks in the
02361         **  main detection engine for each protocol field.
02362         */
02363         Detect(p);
02364         otn_tmp = NULL;
02365 
02366         /*
02367         **  Handle event stuff after we do detection.
02368         **
02369         **  Here's the reason why:
02370         **    - since snort can only handle one logged event per packet, 
02371         **      we only log HttpInspect events if there wasn't one in the
02372         **      detection engine.  I say that events generated in the
02373         **      "advanced generic content matching" engine is more 
02374         **      important than generic events that I can log here.
02375         */
02376         LogEvents(Session, p, iInspectMode);
02377 
02378         /*
02379         **  We set the global detection flag here so that if request pipelines
02380         **  fail, we don't do any detection.
02381         */
02382         do_detect = 0;
02383         iCallDetect = 0;
02384 
02385         p->preprocessors = 0;
02386         p->preprocessors |= PP_STREAM4;
02387 
02388     } while(Session->client.request.pipeline_req);
02389 
02390     return 0;
02391 }
02392 
02393     
02394     
02395 
02396 
02397 
02398 
02399 

Generated on Sun May 14 14:51:16 2006 by  doxygen 1.4.2