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

hi_client.c

Go to the documentation of this file.
00001 /**
00002 **  @file       hi_client.c
00003 **
00004 **  @author     Daniel Roelker <droelker@sourcefire.com>
00005 **
00006 **  @brief      Main file for all the client functions and inspection
00007 **              flow.
00008 **
00009 **  Copyright (C) 2003-2005 Sourcefire,Inc.
00010 **
00011 **  The job of the client module is to analyze and inspect the HTTP
00012 **  protocol, finding where the various fields begin and end.  This must
00013 **  be accomplished in a stateful and stateless manner.
00014 **
00015 **  While the fields are being determined, we also do checks for 
00016 **  normalization, so we don't normalize fields that don't need it.
00017 **
00018 **  Currently, the only fields we check for this is the URI and the
00019 **  parameter fields.
00020 **  
00021 **  NOTES:
00022 **    - 3.8.03:  Initial development.  DJR
00023 **    - 2.4.05:  Added tab_uri_delimiter config option.  AJM.
00024 */
00025 
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include <sys/types.h>
00031 
00032 #include "hi_ui_config.h"
00033 #include "hi_si.h"
00034 #include "hi_mi.h"
00035 #include "hi_client.h"
00036 #include "hi_eo_log.h"
00037 #include "hi_util.h"
00038 #include "hi_util_hbm.h"
00039 #include "hi_return_codes.h"
00040 
00041 #define URI_END  1
00042 #define NO_URI  -1
00043 #define INVALID_HEX_VAL -1
00044 
00045 /**
00046 **  This structure holds pointers to the different sections of an HTTP
00047 **  request.  We need to track where whitespace begins and ends, so we
00048 **  can evaluate the placement of the URI correctly.
00049 **
00050 **  For example,
00051 **
00052 **  GET     / HTTP/1.0
00053 **     ^   ^          
00054 **   start end
00055 **
00056 **  The end space pointers are set to NULL if there is space until the end
00057 **  of the buffer.
00058 */
00059 typedef struct s_URI_PTR
00060 {
00061     u_char *uri;                /* the beginning of the URI */
00062     u_char *uri_end;            /* the end of the URI */
00063     u_char *norm;               /* ptr to first normalization occurence */
00064     u_char *ident;              /* ptr to beginning of the HTTP identifier */
00065     u_char *first_sp_start;     /* beginning of first space delimiter */
00066     u_char *first_sp_end;       /* end of first space delimiter */
00067     u_char *second_sp_start;    /* beginning of second space delimiter */
00068     u_char *second_sp_end;      /* end of second space delimiter */
00069     u_char *param;              /* '?' (beginning of parameter field) */
00070     u_char *delimiter;          /* HTTP URI delimiter (\r\n\) */
00071     u_char *last_dir;           /* ptr to last dir, so we catch long dirs */
00072     u_char *proxy;              /* ptr to the absolute URI */
00073 }  URI_PTR;
00074 
00075 /**
00076 **  This makes passing function arguments much more readable and easier
00077 **  to follow.
00078 */
00079 typedef int (*LOOKUP_FCN)(HI_SESSION *, u_char *, u_char *, u_char **,
00080         URI_PTR *);
00081 
00082 /*
00083 **  The lookup table contains functions for different HTTP delimiters 
00084 **  (like whitespace and the HTTP delimiter \r and \n).
00085 */
00086 static LOOKUP_FCN lookup_table[256];
00087 static int hex_lookup[256];
00088 
00089 /*
00090 **  NAME
00091 **    CheckChunkEncoding::
00092 */
00093 /**
00094 **  This routine checks for chunk encoding anomalies in an HTTP client request
00095 **  packet.
00096 **  
00097 **  We convert potential chunk lengths and test them against the user-defined
00098 **  max chunk length.  We log events on any chunk lengths that are over this
00099 **  defined chunk lengths.
00100 **  
00101 **  Chunks are skipped to save time when the chunk is contained in the packet.
00102 **  
00103 **  We assume coming into this function that we are pointed at the beginning
00104 **  of what may be a chunk length.  That's why the iCheckChunk var is set
00105 **  to 1.
00106 **  
00107 **  @param Session pointer to the Session construct
00108 **  @param start   pointer to where to beginning of buffer
00109 **  @param end     pointer to the end of buffer
00110 **  
00111 **  @return integer
00112 **  
00113 **  @retval HI_SUCCESS      function successful
00114 **  @retval HI_INVALID_ARG  invalid argument
00115 */
00116 static int CheckChunkEncoding(HI_SESSION *Session, u_char *start, u_char *end)
00117 {
00118     int    iChunkLen   = 0;
00119     int    iChunkChars = 0;
00120     int    iCheckChunk = 1;
00121     u_char *ptr;
00122     u_char *jump_ptr;
00123 
00124     if(!start || !end)
00125         return HI_INVALID_ARG;
00126 
00127     ptr = start;
00128 
00129     while(hi_util_in_bounds(start, end, ptr))
00130     {
00131         if(*ptr == '\n' || *ptr == ' ' || *ptr == '\t')
00132         {
00133             if(iCheckChunk && iChunkLen != 0)
00134             {
00135                 if(Session->server_conf->chunk_length < iChunkLen &&
00136                    hi_eo_generate_event(Session, HI_EO_CLIENT_LARGE_CHUNK))
00137                 {
00138                     hi_eo_client_event_log(Session, HI_EO_CLIENT_LARGE_CHUNK,
00139                                            NULL, NULL);
00140                 }
00141 
00142                 jump_ptr = ptr + iChunkLen;
00143 
00144                 if(jump_ptr <= ptr)
00145                 {
00146                     break;
00147                 }
00148 
00149                 if(hi_util_in_bounds(start, end, jump_ptr))
00150                 {
00151                     ptr = jump_ptr;
00152                 }
00153                 else
00154                 {
00155                     /*
00156                     **  Chunk too large for packet, so we bail
00157                     */
00158                     break;
00159                 }
00160             }
00161 
00162             /*
00163             **  If we've already evaluated the chunk, or we have a valid delimiter
00164             **  for handling new chunks, we reset and starting evaluating possible
00165             **  chunk lengths.
00166             */
00167             if(iCheckChunk || *ptr == '\n')
00168             {
00169                 iCheckChunk = 1;
00170                 iChunkLen   = 0;
00171                 iChunkChars = 0;
00172             }
00173 
00174             ptr++;
00175             continue;
00176         }
00177 
00178         if(iCheckChunk)
00179         {
00180             if(hex_lookup[*ptr] == INVALID_HEX_VAL)
00181             {
00182                 if(*ptr == '\r')
00183                 {
00184                     ptr++;
00185 
00186                     if(!hi_util_in_bounds(start, end, ptr))
00187                         break;
00188 
00189                     if(*ptr == '\n')
00190                         continue;
00191                 }
00192                 else if(*ptr == ';')
00193                 {
00194                     /*
00195                     **  This is where we skip through the chunk name=value
00196                     **  field.
00197                     */
00198                     ptr++;
00199 
00200                     while(hi_util_in_bounds(start, end, ptr))
00201                     {
00202                         if(*ptr == '\n')
00203                             break;
00204 
00205                         ptr++;
00206                     }
00207 
00208                     continue;
00209                 }
00210 
00211                 iCheckChunk = 0;
00212                 iChunkLen   = 0;
00213                 iChunkChars = 0;
00214             }
00215             else
00216             {
00217                 if(iChunkChars >= 8)
00218                 {
00219                     iCheckChunk = 0;
00220                     iChunkLen   = 0;
00221                     iChunkChars = 0;
00222                 }
00223                 else
00224                 {
00225                     iChunkLen <<= 4;
00226                     iChunkLen |= (unsigned int)hex_lookup[*ptr];
00227 
00228                     iChunkChars++;
00229                 }
00230             }
00231         }
00232 
00233         ptr++;
00234     }
00235 
00236     return HI_SUCCESS;
00237 }
00238 
00239 /*
00240 **  NAME
00241 **    FindPipelineReq::
00242 */
00243 /**
00244 **  Catch multiple requests per packet, by returning pointer to after the
00245 **  end of the request header if there is another request.
00246 **  
00247 **  There are 4 types of "valid" delimiters that we look for.  They are:
00248 **  "\r\n\r\n"
00249 **  "\r\n\n"
00250 **  "\n\r\n"
00251 **  "\n\n"
00252 **  The only patterns that we really only need to look for are:
00253 **  "\n\r\n"
00254 **  "\n\n"
00255 **  The reason being that these two patterns are suffixes of the other 
00256 **  patterns.  So once we find those, we are all good.
00257 **  
00258 **  @param start pointer to the start of text
00259 **  @param end   pointer to the end of text
00260 **  
00261 **  @return pointer
00262 **  
00263 **  @retval NULL  Did not find pipeline request
00264 **  @retval !NULL Found another possible request.
00265 */
00266 static INLINE u_char *FindPipelineReq(u_char *start, u_char *end)
00267 {
00268     u_char *p;
00269 
00270     if(!start || !end)
00271         return NULL;
00272 
00273     p = start;
00274 
00275     /*
00276     **  We say end - 6 because we need at least six bytes to verify that
00277     **  there is an end to the URI and still a request afterwards.  To be
00278     **  exact, we should only subtract 1, but we are not interested in a
00279     **  1 byte method, uri, etc.
00280     **
00281     **  a.k.a there needs to be data after the initial request to inspect
00282     **  to make it worth our while.
00283     */ 
00284     while(p < (end - 6))
00285     {
00286         if(*p == '\n')
00287         {
00288             p++;
00289 
00290             if(*p < 0x0E)
00291             {
00292                 if(*p == '\r')
00293                 {
00294                     p++;
00295 
00296                     if(*p == '\n')
00297                     {
00298                         return ++p;
00299                     }
00300                 }
00301                 else if(*p == '\n')
00302                 {
00303                     return ++p;
00304                 }
00305             }
00306         }
00307 
00308         p++;
00309     }
00310 
00311     return NULL;
00312 }
00313 
00314 /*
00315 **  NAME
00316 **    IsHttpVersion::
00317 */
00318 /**
00319 **  This checks that there is a version following a space with in an HTTP
00320 **  packet.
00321 **  
00322 **  This function gets called when a whitespace area has ended, and we want
00323 **  to know if a version identifier is followed directly after.  So we look
00324 **  for the rfc standard "HTTP/" and report appropriately.  We also need
00325 **  to make sure that the function succeeds given an end of buffer, so for
00326 **  instance if the buffer ends like "  HTT", we still assume that this is
00327 **  a valid version identifier because of TCP segmentation.
00328 **  
00329 **  We also check for the 0.9 standard of GET URI\r\n.  When we see a \r or
00330 **  a \n, then we just return with the pointer still pointing to that char.
00331 **  The reason is because on the next loop, we'll do the evaluation that
00332 **  we normally do and finish up processing there.
00333 **  
00334 **  @param start pointer to the start of the version identifier
00335 **  @param end   pointer to the end of the buffer (could be the end of the
00336 **               data section, or just to the beginning of the delimiter.
00337 **  
00338 **  @return integer
00339 **  
00340 **  @retval 1 this is an HTTP version identifier
00341 **  @retval 0 this is not an HTTP identifier, or bad parameters
00342 */
00343 static int IsHttpVersion(u_char **ptr, u_char *end)
00344 {
00345     static u_char s_acHttpDelimiter[] = "HTTP/";
00346     static int    s_iHttpDelimiterLen = 5;
00347     int    len;
00348     int    iCtr;
00349 
00350     if(*ptr >= end)
00351     {
00352         return 0;
00353     }
00354 
00355     len = end - *ptr;
00356     if(len > s_iHttpDelimiterLen)
00357     {
00358         len = s_iHttpDelimiterLen;
00359     }
00360 
00361     /*
00362     **  This is where we check for the defunct method again.  This method
00363     **  allows a request of "GET   /index.html    \r[\n]".  So we need to
00364     **  check validate this as a legal identifier.
00365     */
00366     if(**ptr == '\n' || **ptr == '\r')
00367     {
00368         /*
00369         **  We don't increment the pointer because we check for a legal
00370         **  identifier in the delimiter checking.  Read the comments for
00371         **  setting the defunct variable in these functions.
00372         */
00373         return 1;
00374     }
00375 
00376     for(iCtr = 0; iCtr < len; iCtr++)
00377     {
00378         if(s_acHttpDelimiter[iCtr] != (u_char)toupper((int)**ptr))
00379         {
00380             return 0;
00381         }
00382 
00383         (*ptr)++;
00384     }     
00385 
00386     /*
00387     **  This means that we match all the chars that we could given the 
00388     **  remaining length so we should increment the pointer by that much
00389     **  since we don't need to inspect this again.
00390     */
00391     (*ptr)++;
00392 
00393     return 1;
00394 }
00395 
00396 /*
00397 **  NAME
00398 **    find_rfc_delimiter::
00399 */
00400 /**
00401 **  Check for standard RFC HTTP delimiter.
00402 **
00403 **  If we find the delimiter, we return that URI_PTR structures should
00404 **  be checked, which bails us out of the loop.  If there isn't a RFC
00405 **  delimiter, then we bail with a no URI.  Otherwise, we check for out
00406 **  of bounds.
00407 **
00408 **  @param ServerConf pointer to the server configuration
00409 **  @param start      pointer to the start of payload
00410 **  @param end        pointer to the end of the payload
00411 **  @param ptr        pointer to the pointer of the current index
00412 **  @param uri_ptr    pointer to the URI_PTR construct
00413 **  
00414 **  @return integer
00415 **  
00416 **  @retval HI_OUT_OF_BOUNDS 
00417 **  @retval URI_END end of the URI is found, check URI_PTR.
00418 **  @retval NO_URI  malformed delimiter, no URI.
00419 */
00420 static int find_rfc_delimiter(HI_SESSION *Session, u_char *start, 
00421         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00422 {
00423     if(*ptr == start || !uri_ptr->uri)
00424         return NO_URI;
00425 
00426     /*
00427     **  This is important to catch the defunct way of getting URIs without
00428     **  specifying "HTTP/major.minor\r\n\r\n".  This is a quick way for
00429     **  us to tell if we are in that state.
00430     **
00431     **  We check for a legal identifier to deal with the case of
00432     **  "some_of_the_uri_in segmented packet \r\n" in the defunct case.
00433     **  Since we find a "valid" (still defunct) delimiter, we account for
00434     **  it here, so that we don't set the uri_end to the delimiter.
00435     **
00436     **  NOTE:
00437     **  We now assume that the defunct method is in effect and if there is
00438     **  a valid identifier, then we don't update the uri_end because it's
00439     **  already been set when the identifier was validated.
00440     */
00441 
00442     (*ptr)++;
00443     if(!hi_util_in_bounds(start, end, *ptr))
00444     {
00445         return HI_OUT_OF_BOUNDS;
00446     }
00447         
00448     if(**ptr == '\n')
00449     {
00450         uri_ptr->delimiter = (*ptr)-1;
00451 
00452         if(!uri_ptr->ident)
00453             uri_ptr->uri_end = uri_ptr->delimiter;
00454         
00455         return URI_END;
00456     }
00457 
00458     return NO_URI;
00459 }
00460 
00461 /*
00462 **  NAME
00463 **    find_non_rfc_delimiter::
00464 */
00465 /**
00466 **  Check for non standard delimiter '\n'.
00467 **
00468 **  It now appears that apache and iis both take this non-standard 
00469 **  delimiter.  So, we most likely will always look for it, but maybe
00470 **  give off a special alert or something.
00471 **
00472 **  @param ServerConf pointer to the server configuration
00473 **  @param start      pointer to the start of payload
00474 **  @param end        pointer to the end of the payload
00475 **  @param ptr        pointer to the pointer of the current index
00476 **  @param uri_ptr    pointer to the URI_PTR construct  
00477 **  
00478 **  @return integer
00479 **  
00480 **  @retval URI_END delimiter found, end of URI
00481 **  @retval NO_URI  
00482 */
00483 static int find_non_rfc_delimiter(HI_SESSION *Session, u_char *start,
00484         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00485 {
00486     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
00487 
00488     if(*ptr == start || !uri_ptr->uri)
00489         return NO_URI;
00490 
00491     /*
00492     **  This is important to catch the defunct way of getting URIs without
00493     **  specifying "HTTP/major.minor\r\n\r\n".  This is a quick way for
00494     **  us to tell if we are in that state.
00495     **
00496     **  We check for a legal identifier to deal with the case of
00497     **  "some_of_the_uri_in segmented packet \r\n" in the defunct case.
00498     **  Since we find a "valid" (still defunct) delimiter, we account for
00499     **  it here, so that we don't set the uri_end to the delimiter.
00500     **
00501     **  NOTE:
00502     **  We now assume that the defunct method is in effect and if there is
00503     **  a valid identifier, then we don't update the uri_end because it's
00504     **  already been set when the identifier was validated.
00505     */
00506     if(ServerConf->iis_delimiter.on)
00507     {
00508         if(hi_eo_generate_event(Session, ServerConf->iis_delimiter.alert))
00509         {
00510             hi_eo_client_event_log(Session, HI_EO_CLIENT_IIS_DELIMITER,
00511                                    NULL, NULL);
00512         }
00513 
00514         uri_ptr->delimiter = *ptr;
00515         
00516         if(!uri_ptr->ident)
00517             uri_ptr->uri_end = uri_ptr->delimiter;
00518         
00519         return URI_END;
00520     }
00521 
00522     /*
00523     **  This allows us to do something if the delimiter check is not turned
00524     **  on.  Most likely this is worthy of an alert, IF it's not normal to
00525     **  see these requests.
00526     **
00527     **  But for now, we always return true.
00528     */
00529     uri_ptr->delimiter = *ptr;
00530 
00531     if(!uri_ptr->ident)
00532         uri_ptr->uri_end = uri_ptr->delimiter;
00533 
00534     return URI_END;
00535 }
00536 
00537 /*
00538 **  NAME
00539 **    NextNonWhiteSpace::
00540 */
00541 /**
00542 **  Update the URI_PTR fields spaces, find the next non-white space char,
00543 **  and validate the HTTP version identifier after the spaces.
00544 **  
00545 **  This is the main part of the URI algorithm.  This verifies that there
00546 **  isn't too many spaces in the data to be a URI, it checks that after the
00547 **  second space that there is an HTTP identifier or otherwise it's no good.
00548 **  Also, if we've found an identifier after the first whitespace, and
00549 **  find another whitespace, there is no URI.
00550 **  
00551 **  The uri and uri_end pointers are updated in this function depending
00552 **  on what space we are at, and if the space was followed by the HTTP
00553 **  identifier.  (NOTE:  the HTTP delimiter is no longer "HTTP/", but
00554 **  can also be "\r\n", "\n", or "\r".  This is the defunct method, and
00555 **  we deal with it in the IsHttpVersion and delimiter functions.)
00556 **  
00557 **  @param ServerConf pointer to the server configuration
00558 **  @param start      pointer to the start of payload
00559 **  @param end        pointer to the end of the payload
00560 **  @param ptr        pointer to the pointer of the current index
00561 **  @param uri_ptr    pointer to the URI_PTR construct  
00562 **  
00563 **  @return integer
00564 **  
00565 **  @retval HI_SUCCESS       found the next non-whitespace
00566 **  @retval HI_OUT_OF_BOUNDS whitespace to the end of the buffer
00567 **  @retval URI_END          delimiter found, end of URI
00568 **  @retval NO_URI
00569 */
00570 static int NextNonWhiteSpace(HI_SESSION *Session, u_char *start, 
00571         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00572 {
00573     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
00574     u_char **start_sp;
00575     u_char **end_sp;
00576 
00577     /*
00578     **  Horizontal tab is only accepted by apache web servers, not IIS.
00579     **  Some IIS exploits contain a tab (0x09) in the URI, so we don't want
00580     **  to treat it as a URI delimiter and cut off the URI.
00581     */
00582     if ( **ptr == '\t' && !ServerConf->tab_uri_delimiter )
00583     {
00584         (*ptr)++;
00585         return HI_SUCCESS;
00586     }
00587 
00588     /*
00589     **  Reset the identifier, because we've just seen another space.  We
00590     **  should only see the identifier immediately after a space followed
00591     **  by a delimiter.
00592     */
00593     if(uri_ptr->ident)
00594     {
00595         if(ServerConf->non_strict)
00596         {
00597             /*
00598             **  In non-strict mode it is ok to see spaces after the
00599             **  "identifier", so we just increment the ptr and return.
00600             */
00601             (*ptr)++;
00602             return HI_SUCCESS;
00603         }
00604         else
00605         {
00606             /*
00607             **  This means that we've already seen a space and a version
00608             **  identifier, and now that we've seen another space, we know
00609             **  that this can't be the URI so we just bail out with no
00610             **  URI.
00611             */
00612             return NO_URI;
00613         }
00614     }
00615 
00616     uri_ptr->ident = NULL;
00617 
00618     /*
00619     **  We only check for one here, because both should be set if one
00620     **  is.
00621     */
00622     if(uri_ptr->first_sp_end)
00623     {
00624         /*
00625         **  If the second space has been set, then this means that we have   
00626         **  seen a third space, which we shouldn't see in the URI so we
00627         **  are now done and know there is no URI in this packet.
00628         */
00629         if(uri_ptr->second_sp_end)
00630         {
00631             return NO_URI;
00632         }
00633 
00634         /*
00635         **  Since we've seen the second space, we need to update the uri ptr
00636         **  to the end of the first space, since the URI cannot be before the
00637         **  first space.
00638         */
00639         uri_ptr->uri = uri_ptr->first_sp_end;
00640 
00641         uri_ptr->second_sp_start = *ptr;
00642         uri_ptr->second_sp_end = NULL;
00643 
00644         start_sp = &uri_ptr->second_sp_start;
00645         end_sp = &uri_ptr->second_sp_end;
00646     }
00647     else
00648     {
00649         /*
00650         **  This means that there is whitespace at the beginning of the line
00651         **  and we unset the URI so we can set it later if need be.
00652         **
00653         **  This is mainly so we handle data that is all spaces correctly.
00654         **  
00655         **  In the normal case where we've seen text and then the first space,
00656         **  we leave the uri ptr pointing at the beginning of the data, and
00657         **  set the uri end after we've determined where to put it.
00658         */
00659         if(start == *ptr)
00660             uri_ptr->uri = NULL;
00661 
00662 
00663         uri_ptr->first_sp_start = *ptr;
00664         uri_ptr->first_sp_end = NULL;
00665 
00666         start_sp = &uri_ptr->first_sp_start;
00667         end_sp = &uri_ptr->first_sp_end;
00668     }
00669 
00670     while(hi_util_in_bounds(start, end, *ptr))
00671     {
00672         /*
00673         **  Check for whitespace
00674         */
00675         if(**ptr == ' ')
00676         {
00677             (*ptr)++;
00678             continue;
00679         }
00680         else if((**ptr == '\t'))
00681         {
00682             if(ServerConf->apache_whitespace.on)
00683             {
00684                 if(hi_eo_generate_event(Session, 
00685                                         ServerConf->apache_whitespace.alert))
00686                 {
00687                     hi_eo_client_event_log(Session, HI_EO_CLIENT_APACHE_WS,
00688                                            NULL, NULL);
00689                 }
00690 
00691                 (*ptr)++;
00692                 continue;
00693             }
00694             else
00695             {
00696                 return NO_URI;
00697             }
00698         }
00699         else
00700         {
00701             /*
00702             **  This sets the sp_end for whatever space delimiter we are on,
00703             **  whether that is the first space or the second space.
00704             */
00705             *end_sp = *ptr;
00706 
00707             if(!IsHttpVersion(ptr, end))
00708             {
00709                 /*
00710                 **  This is the default method and what we've been doing
00711                 **  since the start of development.
00712                 */
00713                 if(uri_ptr->second_sp_start)
00714                 {
00715                     /*
00716                     **  There is no HTTP version indentifier at the beginning
00717                     **  of the second space, and this means that there is no
00718                     **  URI.
00719                     */
00720                     if(ServerConf->non_strict)
00721                     {
00722                         /*
00723                         **  In non-strict mode, we must assume the URI is
00724                         **  between the first and second space, so now
00725                         **  that we've seen the second space that's the
00726                         **  identifier.
00727                         */
00728                         uri_ptr->ident  = *end_sp;
00729                         uri_ptr->uri_end = *start_sp;
00730                     
00731                         return HI_SUCCESS;
00732                     }
00733                     else
00734                     {
00735                         /*
00736                         **  Since we are in strict mode here, it means that
00737                         **  we haven't seen a valid identifier, so there was
00738                         **  no URI.
00739                         */
00740                         return NO_URI;
00741                     }
00742                 }
00743 
00744                 /*
00745                 **  RESET NECESSARY URI_PTRs HERE.  This is the place where
00746                 **  the uri is updated.  It can only happen once, so do it
00747                 **  right here.
00748                 **
00749                 **  When we get here it means that we have found the end of
00750                 **  the FIRST whitespace, and that there was no delimiter,
00751                 **  so we reset the uri pointers and other related 
00752                 **  pointers.
00753                 */
00754                 uri_ptr->uri      = *end_sp;
00755                 uri_ptr->uri_end  = end;
00756                 uri_ptr->norm     = NULL;
00757                 uri_ptr->last_dir = NULL;
00758                 uri_ptr->param    = NULL;
00759                 uri_ptr->proxy    = NULL;
00760             }
00761             else
00762             {
00763                 /*
00764                 **  Means we found the HTTP version identifier and we reset
00765                 **  the uri_end pointer to point to the beginning of the
00766                 **  whitespace detected.
00767                 **
00768                 **  This works for both "uri_is_here HTTP/1.0" and
00769                 **  "METHOD uri_is_here HTTP/1.0", so it works when the
00770                 **  identifier is after either the first or the second
00771                 **  whitespace.
00772                 */
00773                 uri_ptr->ident   = *end_sp;
00774                 uri_ptr->uri_end = *start_sp;
00775             }
00776 
00777             /*
00778             **  We found a non-whitespace char
00779             */
00780             return HI_SUCCESS;
00781         }
00782     }
00783 
00784     /*
00785     **  This is the case where we've seen text and found a whitespace until
00786     **  the end of the buffer.  In that case, we set the uri_end to the
00787     **  beginning of the whitespace.
00788     */
00789     uri_ptr->uri_end = *start_sp;
00790 
00791     return HI_OUT_OF_BOUNDS;
00792 }
00793 
00794 /*
00795 **  NAME
00796 **    SetPercentNorm::
00797 */
00798 /**
00799 **  Check for percent normalization in the URI buffer.
00800 **  
00801 **  We don't do much here besides check the configuration, set the pointer,
00802 **  and continue processing.
00803 **
00804 **  @param ServerConf pointer to the server configuration
00805 **  @param start      pointer to the start of payload
00806 **  @param end        pointer to the end of the payload
00807 **  @param ptr        pointer to the pointer of the current index
00808 **  @param uri_ptr    pointer to the URI_PTR construct  
00809 **  
00810 **  @return integer
00811 **  
00812 **  @retval HI_SUCCESS function successful
00813 */
00814 static int SetPercentNorm(HI_SESSION *Session, u_char *start,
00815         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00816 {
00817     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
00818 
00819     if(!uri_ptr->norm && !uri_ptr->ident)
00820     {
00821         if(ServerConf->ascii.on)
00822         {
00823             uri_ptr->norm = *ptr;
00824         }
00825     }
00826 
00827     (*ptr)++;
00828    
00829     return HI_SUCCESS;
00830 }
00831 
00832 /*
00833 **  NAME
00834 **    CheckLongDir::
00835 */
00836 /**
00837 **  We check the directory length against the global config.
00838 **  
00839 **  @param Session pointer to the current session
00840 **  @param uri_ptr pointer to the URI state
00841 **  @param ptr     pointer to the current index in buffer
00842 **  
00843 **  @return integer
00844 **  
00845 **  @retval HI_SUCCESS
00846 */
00847 static INLINE int CheckLongDir(HI_SESSION *Session, URI_PTR *uri_ptr, 
00848                                u_char *ptr)
00849 {
00850     int iDirLen;
00851 
00852     /*
00853     **  Check for oversize directory
00854     */
00855     if(Session->server_conf->long_dir && uri_ptr->last_dir &&
00856        !uri_ptr->param)
00857     {
00858         iDirLen = ptr - uri_ptr->last_dir;
00859 
00860         if(iDirLen > Session->server_conf->long_dir &&
00861            hi_eo_generate_event(Session, HI_EO_CLIENT_OVERSIZE_DIR))
00862         {
00863             hi_eo_client_event_log(Session, HI_EO_CLIENT_OVERSIZE_DIR,
00864                                    NULL, NULL);
00865         }
00866     }
00867 
00868     return HI_SUCCESS;
00869 
00870 }
00871 
00872 /*
00873 **  NAME
00874 **    SetSlashNorm::
00875 */
00876 /**
00877 **  Check for any directory traversal or multi-slash normalization.
00878 **  
00879 **  @param ServerConf pointer to the server configuration
00880 **  @param start      pointer to the start of payload
00881 **  @param end        pointer to the end of the payload
00882 **  @param ptr        pointer to the pointer of the current index
00883 **  @param uri_ptr    pointer to the URI_PTR construct  
00884 **  
00885 **  @return integer
00886 **  
00887 **  @retval HI_SUCCESS       function successful
00888 **  @retval HI_OUT_OF_BOUNDS reached the end of the buffer
00889 */
00890 static int SetSlashNorm(HI_SESSION *Session, u_char *start,
00891         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00892 {
00893     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
00894 
00895     CheckLongDir(Session, uri_ptr, *ptr);
00896     uri_ptr->last_dir = *ptr;
00897 
00898     if(!uri_ptr->norm && !uri_ptr->ident)
00899     {
00900 
00901         uri_ptr->norm = *ptr;
00902 
00903         (*ptr)++;
00904 
00905         if(!hi_util_in_bounds(start,end, *ptr))
00906         {
00907             /*
00908             **  This is the case where there is a slash as the last char
00909             **  and we don't want to normalize that since there really
00910             **  is nothing to normalize.
00911             */
00912             uri_ptr->norm = NULL;
00913             return HI_OUT_OF_BOUNDS;
00914         }
00915 
00916         /*
00917         **  Check for directory traversals
00918         */
00919         if(ServerConf->directory.on)
00920         {
00921             if(**ptr == '.')
00922             {
00923                 (*ptr)++;
00924                 if(!hi_util_in_bounds(start, end, *ptr))
00925                 {
00926                     uri_ptr->norm = NULL;
00927                     return HI_OUT_OF_BOUNDS;
00928                 }
00929 
00930                 if(**ptr == '.' || ** ptr == '/')
00931                 {
00932                     return HI_SUCCESS;
00933                 }
00934             }
00935         }
00936 
00937         /*
00938         **  Check for multiple slash normalization
00939         */
00940         if(ServerConf->multiple_slash.on)
00941         {
00942             if(**ptr == '/')
00943             {
00944                 return HI_SUCCESS;
00945             }
00946         }
00947 
00948         uri_ptr->norm = NULL;
00949         return HI_SUCCESS;
00950     }
00951 
00952     (*ptr)++;
00953 
00954     return HI_SUCCESS;
00955 }
00956 
00957 /*
00958 **  NAME
00959 **    SetBackSlashNorm::
00960 */
00961 /**
00962 **  Check for backslashes and if we need to normalize.
00963 **  
00964 **  This really just checks the configuration option, and sets the norm
00965 **  variable if applicable.
00966 **  
00967 **  @param ServerConf pointer to the server configuration
00968 **  @param start      pointer to the start of payload
00969 **  @param end        pointer to the end of the payload
00970 **  @param ptr        pointer to the pointer of the current index
00971 **  @param uri_ptr    pointer to the URI_PTR construct  
00972 **  
00973 **  @return integer
00974 **  
00975 **  @retval HI_SUCCESS       function successful
00976 */
00977 static int SetBackSlashNorm(HI_SESSION *Session, u_char *start,
00978         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
00979 {
00980     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
00981 
00982     if(!uri_ptr->norm && !uri_ptr->ident)
00983     {
00984         if(ServerConf->iis_backslash.on)
00985         {
00986             uri_ptr->norm = *ptr;
00987         }
00988     }
00989 
00990     (*ptr)++;
00991 
00992     return HI_SUCCESS;
00993 }
00994 
00995 /*
00996 **  NAME
00997 **    SetBinaryNorm::
00998 */
00999 /**
01000 **  Look for non-ASCII chars in the URI.
01001 **  
01002 **  We look for these chars in the URI and set the normalization variable
01003 **  if it's not already set.  I think we really only need this for IIS
01004 **  servers, but we may want to know if it's in the URI too.
01005 **  
01006 **  @param ServerConf pointer to the server configuration
01007 **  @param start      pointer to the start of payload
01008 **  @param end        pointer to the end of the payload
01009 **  @param ptr        pointer to the pointer of the current index
01010 **  @param uri_ptr    pointer to the URI_PTR construct  
01011 **  
01012 **  @return integer
01013 **  
01014 **  @retval HI_SUCCESS       function successful
01015 */
01016 static int SetBinaryNorm(HI_SESSION *Session, u_char *start,
01017         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
01018 {
01019     if(!uri_ptr->norm && !uri_ptr->ident)
01020     {
01021         uri_ptr->norm = *ptr;
01022     }
01023 
01024     (*ptr)++;
01025 
01026     return HI_SUCCESS;
01027 }
01028 
01029 /*
01030 **  NAME
01031 **    SetParamField::
01032 */
01033 /**
01034 **  This function sets the parameter field as the first '?'.  The big thing
01035 **  is that we set the param value, so we don't false positive long dir
01036 **  events when it's really just a long parameter field.
01037 **  
01038 **  @param ServerConf pointer to the server configuration
01039 **  @param start      pointer to the start of payload
01040 **  @param end        pointer to the end of the payload
01041 **  @param ptr        pointer to the pointer of the current index
01042 **  @param uri_ptr    pointer to the URI_PTR construct  
01043 **  
01044 **  @return integer
01045 **  
01046 **  @retval HI_SUCCESS       function successful
01047 */
01048 static int SetParamField(HI_SESSION *Session, u_char *start,
01049         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
01050 {
01051     if(!uri_ptr->ident)
01052     {
01053         uri_ptr->param = *ptr;
01054     }
01055 
01056     (*ptr)++;
01057 
01058     return HI_SUCCESS;
01059 }
01060 /*
01061 **  NAME
01062 **    SetProxy::
01063 */
01064 /**
01065 **  This function checks for an absolute URI in the URI.
01066 **  
01067 **  @param ServerConf pointer to the server configuration
01068 **  @param start      pointer to the start of payload
01069 **  @param end        pointer to the end of the payload
01070 **  @param ptr        pointer to the pointer of the current index
01071 **  @param uri_ptr    pointer to the URI_PTR construct  
01072 **  
01073 **  @return integer
01074 **  
01075 **  @retval HI_SUCCESS       function successful
01076 */
01077 static int SetProxy(HI_SESSION *Session, u_char *start,
01078         u_char *end, u_char **ptr, URI_PTR *uri_ptr)
01079 {
01080     HTTPINSPECT_CONF *ServerConf = Session->server_conf;
01081 
01082     if(!uri_ptr->ident && !uri_ptr->last_dir)
01083     {
01084         if(Session->global_conf->proxy_alert && !ServerConf->allow_proxy)
01085         {
01086             if(hi_util_in_bounds(start, end, ((*ptr)+2)))
01087             {
01088                 if(*((*ptr)+1) == '/' && *((*ptr)+1) == '/')
01089                 {
01090                     uri_ptr->proxy = *ptr;
01091                 }
01092             }
01093         }
01094     }
01095 
01096     (*ptr)++;
01097 
01098     return HI_SUCCESS;
01099 }
01100 
01101 /*
01102 **  NAME
01103 **    SetClientVars::
01104 */
01105 /**
01106 **  This is where we set the HI_CLIENT values that we found during URI
01107 **  discovery.  This also covers checking these values for errors.
01108 **  
01109 **  @param Client   pointer to HI_CLIENT structure
01110 **  @param uri_ptr  pointer to the uri data
01111 **  
01112 **  @return integer
01113 **  
01114 **  @retval HI_NONFATAL_ERR problem with the uri values.
01115 **  @retval HI_SUCCESS      values set successfully
01116 */
01117 static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize)
01118 {
01119     /*
01120     **  We got here either because we found the delimiter or we are
01121     **  out of bounds.
01122     */
01123 
01124     /*
01125     if(uri_ptr->first_sp_start)
01126         printf("** first_start  = %c\n", *uri_ptr->first_sp_start);
01127     if(uri_ptr->first_sp_end)
01128         printf("** first_end    = %c\n", *uri_ptr->first_sp_end);
01129     if(uri_ptr->second_sp_start)
01130         printf("** second_start = %c\n", *uri_ptr->second_sp_start);
01131     if(uri_ptr->second_sp_end)
01132         printf("** second_end   = %c\n", *uri_ptr->second_sp_end);
01133     if(uri_ptr->delimiter)
01134         printf("** delimiter    = %c\n", *uri_ptr->delimiter);
01135     
01136     if(uri_ptr->uri)
01137         printf("** uri          = %c\n", *uri_ptr->uri);
01138     if(uri_ptr->norm)
01139         printf("** norm         = %.2x\n", *uri_ptr->norm);
01140     */
01141 
01142     /*
01143     **  This means that there was only spaces or delimiters within the 
01144     **  complete URI.  In this case, there is no valid URI so we just
01145     **  return such.
01146     */
01147     if(uri_ptr->uri == NULL)
01148     {
01149         return HI_NONFATAL_ERR;
01150     }
01151 
01152     /*
01153     **  This is where we set the Session variables before moving into more
01154     **  HttpInspect processing.  If we don't get to this point, then we don't
01155     **  need to set these variables since we would have aborted with a
01156     **  NONFATAL_ERR.
01157     */
01158     Client->request.uri      = uri_ptr->uri;
01159     Client->request.uri_size = uri_ptr->uri_end - uri_ptr->uri;
01160     Client->request.uri_norm = uri_ptr->norm;
01161 
01162     /*
01163     **  LAST RESORT:
01164     **
01165     **  This is one of the last checks we do to make sure that we didn't
01166     **  mess up or anything.
01167     */
01168     if(Client->request.uri_size < 1 || Client->request.uri_size > dsize)
01169     {
01170         /*
01171         **  Bad stuff, let's just bail.
01172         */
01173         return HI_NONFATAL_ERR;
01174     }
01175 
01176     /*
01177     printf("** Norm = %s\n", Client->request.uri_norm ? "YES" : "NO");
01178     printf("** URI: |%.*s| size = %u\n", Client->request.uri_size,
01179            Client->request.uri, Client->request.uri_size);
01180     */
01181 
01182     return HI_SUCCESS;
01183 }
01184 
01185 /*
01186 **  NAME
01187 **    StatelessInspection::
01188 */
01189 /**
01190 **  Find the URI and determine whether the URI needs to be normalized.
01191 **  
01192 **  This is a big step in stateless inspection, because we need to reliably
01193 **  find the URI and when possible filter out non-URIs.  We do this using a
01194 **  simple state machine that is based on characters found in the data
01195 **  buffer.
01196 **  
01197 **  Another important aspect of the stateless inspection is the ability to
01198 **  track and inspect pipelined requests.  It is VERY IMPORTANT to reset the
01199 **  pipeline_req pointer, since we don't memset the whole structure.  This
01200 **  pointer is reset in the hi_si_session_inspection() function.  Check there
01201 **  for more details.
01202 **  
01203 **  Normalization is detected when we are looking at the packet for the URI.
01204 **  We look for the following issues:
01205 **      - ////
01206 **      - /../
01207 **      - /./
01208 **      - non-ascii charss
01209 **      - %
01210 **      - \
01211 **  When these things are seen we point to the first occurence in the URI, or
01212 **  where we have to start normalizing.  If the URI is updated to a new
01213 **  pointer, then the normalization pointer is reset and we start over.
01214 **  Using this method should cut down the memcpy()s per URI, since most
01215 **  URIs are not normalized.
01216 **  
01217 **  If this function returns HI_NONFATAL_ERR, we return out of mode_inspection
01218 **  with an error and abort HttpInspect processing, and continue on with
01219 **  any other processing we do.  The Session parameters that we use here are
01220 **  reset in the next time that we do session_inspection, so we don't do
01221 **  any initialization here.
01222 **  
01223 **  @param Session pointer to the HTTP session
01224 **  @param data    pointer to the start of the packet payload
01225 **  @param dsize   size of the payload
01226 **  
01227 **  @return integer
01228 **  
01229 **  @retval HI_INVALID_ARG  invalid argument
01230 **  @retval HI_NONFATAL_ERR no URI detected
01231 **  @retval HI_SUCCESS      URI detected and Session pointers updated
01232 */
01233 static int StatelessInspection(HI_SESSION *Session, unsigned char *data,
01234         int dsize)
01235 {
01236     HTTPINSPECT_CONF *ServerConf;
01237     HTTPINSPECT_CONF *ClientConf;
01238     HI_CLIENT *Client;
01239     URI_PTR uri_ptr;
01240     u_char *start;
01241     u_char *end;
01242     u_char *ptr;
01243     int iRet;
01244 
01245     if(!Session || !data || dsize < 1)
01246     {
01247         return HI_INVALID_ARG;
01248     }
01249 
01250     ServerConf = Session->server_conf;
01251     if(!ServerConf)
01252     {
01253         return HI_INVALID_ARG;
01254     }
01255 
01256     ClientConf = Session->client_conf;
01257     if(!ClientConf)
01258     {
01259         return HI_INVALID_ARG;
01260     }
01261 
01262     Client = &Session->client;
01263 
01264     memset(&uri_ptr, 0x00, sizeof(URI_PTR));
01265 
01266     /*
01267     **  We set the starting boundary depending on whether this request is
01268     **  a normal request or a pipeline request.  The end boundary is always
01269     **  the same whether it is a pipeline request or other.
01270     */
01271     if(Client->request.pipeline_req)
01272     {
01273         start = Client->request.pipeline_req;
01274     }
01275     else
01276     {
01277         start = data;
01278     }
01279 
01280     end   = data + dsize;
01281 
01282     ptr = start;
01283 
01284     /*
01285     **  Apache and IIS strike again . . . Thanks Kanatoko
01286     **    - Ignore CRLFs at the beginning of the request.
01287     */
01288     while(hi_util_in_bounds(start, end, ptr))
01289     {
01290         if(*ptr < 0x21)
01291         {
01292             if(*ptr < 0x0E && *ptr > 0x08)
01293             {
01294                 ptr++;
01295                 continue;
01296             }
01297             else
01298             {
01299                 if(*ptr == 0x20)
01300                 {
01301                     ptr++;
01302                     continue;
01303                 }
01304             }
01305         }
01306         
01307         break;
01308     }
01309 
01310     uri_ptr.uri = ptr;
01311     uri_ptr.uri_end = end;
01312 
01313     /*
01314     **  This loop compares each char to an array of functions
01315     **  (one for each char) and calling that function if there is one.
01316     **  
01317     **  If there is no function, then we just increment the char ptr and
01318     **  continue processing.
01319     **
01320     **  If there is a function, we call that function and process.  It's
01321     **  important to note that the function that is called is responsible
01322     **  for incrementing the ptr to the next char to be inspected.  The
01323     **  loop does not increment the pointer when a function is called to
01324     **  allow the maximum flexibility to the functions.
01325     */
01326     while(hi_util_in_bounds(start, end, ptr))
01327     {
01328         if(lookup_table[*ptr])
01329         {
01330             if((iRet = (lookup_table[*ptr])(Session, start, end,
01331                             &ptr, &uri_ptr)))
01332             {
01333                 if(iRet == URI_END)
01334                 {
01335                     /*
01336                     **  You found a URI, let's break and check it out.
01337                     */
01338                     break;
01339                 }
01340                 else if(iRet == HI_OUT_OF_BOUNDS)
01341                 {
01342                     /*
01343                     **  Means you've reached the end of the buffer.  THIS
01344                     **  DOESN'T MEAN YOU HAVEN'T FOUND A URI.
01345                     */
01346                     break;
01347                 }
01348                 else /* NO_URI */
01349                 {
01350                     /*
01351                     **  Check for chunk encoding, because the delimiter can
01352                     **  also be a space, which would look like a pipeline request
01353                     **  to us if we don't do this first.
01354                     */
01355                     if(Session->server_conf->chunk_length)
01356                             CheckChunkEncoding(Session, start, end);
01357 
01358                     /*
01359                     **  We only inspect the packet for another pipeline
01360                     **  request if there wasn't a previous pipeline request.
01361                     **  The reason that we do this is because 
01362                     */  
01363                     if(!Client->request.pipeline_req)
01364                     {
01365                         /*
01366                         **  Just because there was no URI in the first part
01367                         **  the packet, doesn't mean that this isn't a
01368                         **  pipelined request that has been segmented.
01369                         */
01370                         if(!ServerConf->no_pipeline)
01371                         {
01372                             if((Client->request.pipeline_req =
01373                                 FindPipelineReq(ptr, end)))
01374                             {
01375                                 return HI_SUCCESS;
01376                             }
01377                         }
01378                     }
01379 
01380                     return HI_NONFATAL_ERR;
01381                 }
01382             }
01383             else
01384             {
01385                 /*
01386                 **  This means that we found the next non-whitespace char
01387                 **  and since we are already pointed there, so we just
01388                 **  continue.
01389                 */
01390                 continue;
01391             }
01392         }
01393 
01394         ptr++;
01395     }
01396 
01397     /*
01398     **  If there is a pipelined request in this packet, we should always
01399     **  see the first space followed by text (which is the URI).  Without
01400     **  that first space, then we never get to the URI, so we should just
01401     **  return, since there is nothing else to inspect.
01402     */
01403     if(Client->request.pipeline_req)
01404     {
01405         if(uri_ptr.uri != uri_ptr.first_sp_end)
01406         {
01407             if(Session->server_conf->chunk_length)
01408                 CheckChunkEncoding(Session, start, end);
01409 
01410             return HI_NONFATAL_ERR;
01411         }
01412     }
01413 
01414     /*
01415     **  We set the HI_CLIENT variables from the URI_PTR structure.  We also
01416     **  do error checking for the values in this routine as well.
01417     */
01418     if((iRet = SetClientVars(Client, &uri_ptr, dsize)))
01419     {
01420         return iRet;
01421     }
01422 
01423     /*
01424     **  One last check for an oversize directory.  This gets the long
01425     **  directory when there is a beginning slash and no other slashes
01426     **  until the end of the packet.
01427     **
01428     **  We do this check after we set the variables, just in case there
01429     **  was some errors while setting the variables.  This could save some
01430     **  false positives on a bad URI setting.
01431     */
01432     if(uri_ptr.uri_end)
01433         CheckLongDir(Session, &uri_ptr, uri_ptr.uri_end);
01434 
01435     /*
01436     **  Check for absolute URI and alert for proxy comm if necessary
01437     **
01438     **  NOTE:
01439     **    Also check ClientConf for proxy configuration so we don't
01440     **    alert on outbound requests from legitimate proxies.
01441     */
01442     if(uri_ptr.proxy && Session->global_conf->proxy_alert &&
01443        (!ServerConf->allow_proxy && !ClientConf->allow_proxy))
01444     {
01445         if(hi_eo_generate_event(Session, HI_EO_CLIENT_PROXY_USE))
01446         {
01447             hi_eo_client_event_log(Session, HI_EO_CLIENT_PROXY_USE, 
01448                     NULL, NULL);
01449         }
01450     }
01451 
01452     /*
01453     **  Find the next pipeline request, if one is there.  If we don't find
01454     **  a pipeline request, then we return NULL here, so this is always
01455     **  set to the correct value.
01456     */
01457     if(!ServerConf->no_pipeline)
01458     {
01459         Client->request.pipeline_req = FindPipelineReq(uri_ptr.delimiter, end);
01460     }
01461     else
01462     {
01463         Client->request.pipeline_req = NULL;
01464     }
01465 
01466     if(Session->server_conf->chunk_length)
01467         CheckChunkEncoding(Session, uri_ptr.delimiter, end);
01468 
01469     return HI_SUCCESS;
01470 }
01471 
01472 int hi_client_inspection(void *S, unsigned char *data, int dsize)
01473 {
01474     HTTPINSPECT_GLOBAL_CONF *GlobalConf;
01475     HI_SESSION *Session;
01476 
01477     int iRet;
01478 
01479     if(!S || !data || dsize < 1)
01480     {
01481         return HI_INVALID_ARG;
01482     }
01483 
01484     Session = (HI_SESSION *)S;
01485 
01486     if(!Session->global_conf)
01487     {
01488         return HI_INVALID_ARG;
01489     }
01490 
01491     GlobalConf = Session->global_conf;
01492 
01493     /*
01494     **  We inspect the HTTP protocol in either stateful mode or
01495     **  stateless mode.
01496     */
01497     if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL)
01498     {
01499         /*
01500         **  This is where we do stateful inspection.
01501         */
01502         return HI_NONFATAL_ERR;
01503     }
01504     else
01505     {
01506         /*
01507         **  Otherwise we assume stateless inspection
01508         */
01509         if((iRet = StatelessInspection(Session, data, dsize)))
01510         {
01511             return iRet;
01512         }
01513     }
01514 
01515     return HI_SUCCESS;
01516 }
01517 
01518 /*
01519 **  NAME
01520 **    hi_client_init::
01521 */
01522 /**
01523 **  Initializes arrays and search algorithms depending on the type of
01524 **  inspection that we are doing.
01525 **  
01526 **  @param GlobalConf pointer to the global configuration
01527 **  
01528 **  @return integer
01529 **  
01530 **  @retval HI_SUCCESS function successful.
01531 */
01532 int hi_client_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf)
01533 {
01534     int iCtr;
01535     int iNum;
01536 
01537     if(GlobalConf->inspection_type == HI_UI_CONFIG_STATEFUL)
01538     {
01539         /*
01540         **  We don't have to do anything here yet.
01541         */
01542     }
01543     else
01544     {
01545         memset(lookup_table, 0x00, sizeof(lookup_table));
01546         memset(hex_lookup, -1, sizeof(hex_lookup));
01547 
01548         /*
01549         **  Set up the non-ASCII register for processing.
01550         */
01551         for(iCtr = 0x80; iCtr <= 0xff; iCtr++)
01552         {
01553             lookup_table[iCtr] = SetBinaryNorm;
01554         }
01555         lookup_table[0x00] = SetBinaryNorm;
01556 
01557         lookup_table[' ']  = NextNonWhiteSpace;
01558         lookup_table['\t'] = NextNonWhiteSpace;
01559         lookup_table['\r'] = find_rfc_delimiter;
01560         lookup_table['\n'] = find_non_rfc_delimiter;
01561 
01562         /*
01563         **  ASCII encoding
01564         */
01565         lookup_table['%']  = SetPercentNorm;
01566 
01567         /*
01568         **  Looking for multiple slashes
01569         */
01570         lookup_table['/']  = SetSlashNorm;
01571 
01572         /*
01573         **  Looking for backslashs
01574         */
01575         lookup_table['\\'] = SetBackSlashNorm;
01576 
01577         /*
01578         **  Look up parameter field, so we don't alert on long directory
01579         **  strings, when the next slash in the parameter field.
01580         */
01581         lookup_table['?'] = SetParamField;
01582 
01583         /*
01584         **  Look for absolute URI and proxy communication.
01585         */
01586         lookup_table[':'] = SetProxy;
01587 
01588         /*
01589         **  Set up the hex array
01590         */
01591         iNum = 0;
01592         for(iCtr = 48; iCtr < 58; iCtr++)
01593         {
01594             hex_lookup[iCtr] = iNum;
01595             iNum++;
01596         }
01597 
01598         /*
01599         **  Set the upper case values.
01600         */
01601         iNum = 10;
01602         for(iCtr = 65; iCtr < 71; iCtr++)
01603         {
01604             hex_lookup[iCtr] = iNum;
01605             iNum++;
01606         }
01607 
01608         /*
01609         **  Set the lower case values.
01610         */
01611         iNum = 10;
01612         for(iCtr = 97; iCtr < 103; iCtr++)
01613         {
01614             hex_lookup[iCtr] = iNum;
01615             iNum++;
01616         }
01617     }
01618 
01619     return HI_SUCCESS;
01620 }
01621 
01622 
01623 
01624 /**
01625 **  This was just an initial testing program for these functions.
01626 */
01627 #ifdef TEST_ME
01628 
01629 #include <sys/socket.h>
01630 #include <netinet/in.h>
01631 #include <arpa/inet.h>
01632 
01633 int main(int argc, char **argv)
01634 {
01635     HTTPINSPECT_GLOBAL_CONF GlobalConf;
01636     HI_SESSION *Session;
01637     HI_SI_INPUT SiInput;
01638     int iInspectMode = 0;
01639     int iRet;
01640     char data[] = "Hdslkfjaslfkj    HTTP/00000.111111";
01641 
01642     if((iRet = hi_ui_config_init_global_conf(&GlobalConf)))
01643     {
01644         printf("** error during global init.\n");
01645         return iRet;
01646     }
01647 
01648     if((iRet = hi_ui_config_default(&GlobalConf)))
01649     {
01650         printf("** error config default.\n");
01651         return iRet;
01652     }
01653 
01654     hi_ui_config_print_config(&GlobalConf);
01655 
01656     if((iRet = hi_client_init(&GlobalConf)))
01657     {
01658         printf("** error client init\n");
01659         return iRet;
01660     }
01661     
01662     SiInput.sip = inet_addr("1.1.1.1");
01663     SiInput.sip = inet_addr("1.1.1.2");
01664     SiInput.dport = 80;
01665     SiInput.sport = 7880;
01666     
01667     if((iRet = hi_si_session_inspection(&GlobalConf, &Session, &SiInput,
01668                     &iInspectMode)))
01669     {
01670         printf("** error session inspection\n");
01671         return iRet;
01672     }
01673 
01674     printf("** iInspectMode = %d\n", iInspectMode);
01675     if((iRet = hi_mi_mode_inspection(Session, iInspectMode, data, 
01676                     strlen(data))))
01677     {
01678         printf("** error mode_inspection\n");
01679         return iRet;
01680     }
01681 
01682     return 0;
01683 }
01684 #endif
01685     
01686     

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