]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
sync 297 http xff, swf, and pdf updates
authorRuss Combs <rucombs@cisco.com>
Sat, 21 Feb 2015 17:42:55 +0000 (12:42 -0500)
committerRuss Combs <rucombs@cisco.com>
Sat, 21 Feb 2015 17:42:55 +0000 (12:42 -0500)
27 files changed:
ChangeLog
src/service_inspectors/http_inspect/CMakeLists.txt
src/service_inspectors/http_inspect/Makefile.am
src/service_inspectors/http_inspect/hi_client.cc
src/service_inspectors/http_inspect/hi_client.h
src/service_inspectors/http_inspect/hi_client_stateful.h [deleted file]
src/service_inspectors/http_inspect/hi_events.h
src/service_inspectors/http_inspect/hi_file_decomp.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_file_decomp.h [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_file_decomp_pdf.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_file_decomp_pdf.h [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_file_decomp_swf.cc [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_file_decomp_swf.h [new file with mode: 0644]
src/service_inspectors/http_inspect/hi_main.cc
src/service_inspectors/http_inspect/hi_main.h
src/service_inspectors/http_inspect/hi_mi.cc
src/service_inspectors/http_inspect/hi_mi.h
src/service_inspectors/http_inspect/hi_module.cc
src/service_inspectors/http_inspect/hi_norm.cc
src/service_inspectors/http_inspect/hi_norm.h
src/service_inspectors/http_inspect/hi_server.cc
src/service_inspectors/http_inspect/hi_server.h
src/service_inspectors/http_inspect/hi_server_norm.cc
src/service_inspectors/http_inspect/hi_server_norm.h
src/service_inspectors/http_inspect/hi_si.h
src/service_inspectors/http_inspect/hi_ui_config.h
src/service_inspectors/http_inspect/http_inspect.cc

index ce0192d88037920581f3049f137fcc0376fb7378..c900aa8d987eb15da04fb831672ca113b10b8094 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Pending - build 139
+
+-- sync 297 http xff, swf, and pdf updates
+
 15/02/20 - build 138
 
 -- sync ftp with 297; replace stream event callbacks with FlowData virtuals
index 27e3c4818b7a44bf462c2e17348e7f2b06d18640..f643fd2b1f3332fb1c488b92cc5172aa610007fe 100644 (file)
@@ -9,9 +9,14 @@ set (FILE_LIST
     hi_client.h
     hi_client_norm.cc 
     hi_client_norm.h
-    hi_client_stateful.h
     hi_cmd_lookup.cc 
     hi_cmd_lookup.h
+    hi_file_decomp.cc
+    hi_file_decomp.h
+    hi_file_decomp_pdf.cc
+    hi_file_decomp_pdf.h
+    hi_file_decomp_swf.cc
+    hi_file_decomp_swf.h
     hi_include.h
     hi_mi.cc 
     hi_mi.h
index e037f072a12ed580d860896e76774332541df2ed..135ed08c46254045814bf48ce13c95a5131fc7ef 100644 (file)
@@ -6,9 +6,11 @@ hi_main.cc hi_main.h \
 hi_ad.cc hi_ad.h \
 hi_client.cc hi_client.h \
 hi_client_norm.cc hi_client_norm.h \
-hi_client_stateful.h \
 hi_cmd_lookup.cc hi_cmd_lookup.h \
 hi_events.cc hi_events.h \
+hi_file_decomp.cc hi_file_decomp.h \
+hi_file_decomp_pdf.cc hi_file_decomp_pdf.h \
+hi_file_decomp_swf.cc hi_file_decomp_swf.h \
 hi_include.h \
 hi_mi.cc hi_mi.h \
 hi_module.cc hi_module.h \
index 6cded8df6d60fe8d602e26ef33bf00dbc62e5442..a5e922002b45cb0ae274453d50a1cf86ae5e18eb 100644 (file)
 #define HEADER_LENGTH__COOKIE 6
 #define HEADER_NAME__CONTENT_LENGTH "Content-length"
 #define HEADER_LENGTH__CONTENT_LENGTH 14
-#define HEADER_NAME__XFF "X-Forwarded-For"
-#define HEADER_LENGTH__XFF 15
-#define HEADER_NAME__TRUE_IP "True-Client-IP"
-#define HEADER_LENGTH__TRUE_IP 14
+#define HEADER_NAME__XFF HI_UI_CONFIG_XFF_FIELD_NAME
+#define HEADER_LENGTH__XFF (sizeof(HEADER_NAME__XFF)-1)
+#define HEADER_NAME__TRUE_IP HI_UI_CONFIG_TCI_FIELD_NAME
+#define HEADER_LENGTH__TRUE_IP (sizeof(HEADER_NAME__TRUE_IP)-1)
 #define HEADER_NAME__HOSTNAME "Host"
 #define HEADER_LENGTH__HOSTNAME 4
 #define HEADER_NAME__TRANSFER_ENCODING "Transfer-encoding"
 const u_char *proxy_start = NULL;
 const u_char *proxy_end = NULL;
 
+// FIXIT-L for 2.9.7 code not yet ported in
+/*static const char *g_field_names[] =
+{
+    HEADER_NAME__COOKIE,
+    HEADER_NAME__CONTENT_LENGTH,
+    HEADER_NAME__XFF,
+    HEADER_NAME__TRUE_IP,
+    HEADER_NAME__HOSTNAME,
+    HEADER_NAME__TRANSFER_ENCODING,
+    HEADER_NAME__CONTENT_TYPE,
+    NULL
+};*/
+
 /**  This makes passing function arguments much more readable and easier
 **  to follow.
 */
@@ -124,7 +137,7 @@ LOOKUP_FCN lookup_table[256];
 */
 int CheckChunkEncoding(HI_SESSION *session, const u_char *start, const u_char *end,
         const u_char **post_end, u_char *iChunkBuf, uint32_t max_size,
-        uint32_t chunk_remainder, uint32_t *updated_chunk_remainder, uint32_t *chunkRead, HttpsessionData *hsd,
+        uint32_t chunk_remainder, uint32_t *updated_chunk_remainder, uint32_t *chunkRead, HttpSessionData *hsd,
         int iInspectMode)
 {
     uint32_t iChunkLen   = 0;
@@ -1371,7 +1384,6 @@ static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize)
         printf("** second_end   = %c\n", *uri_ptr->second_sp_end);
     if(uri_ptr->delimiter)
         printf("** delimiter    = %c\n", *uri_ptr->delimiter);
-
     if(uri_ptr->uri)
         printf("** uri          = %c\n", *uri_ptr->uri);
     if(uri_ptr->norm)
@@ -1404,11 +1416,8 @@ static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize)
     **  This is one of the last checks we do to make sure that we didn't
     **  mess up or anything.
     */
-    if(Client->request.uri_size < 1 || Client->request.uri_size > dsize)
+    if(Client->request.uri_size > dsize)
     {
-        /*
-        **  Bad stuff, let's just bail.
-        */
         return HI_NONFATAL_ERR;
     }
 
@@ -1424,7 +1433,7 @@ static int SetClientVars(HI_CLIENT *Client, URI_PTR *uri_ptr, u_int dsize)
 static inline int hi_client_extract_post(
     HI_SESSION *session, HTTPINSPECT_CONF *ServerConf,
     const u_char *ptr, const u_char *end, URI_PTR *result,
-    int content_length, bool is_chunked, HttpsessionData *hsd)
+    int content_length, bool is_chunked, HttpSessionData *hsd)
 {
     const u_char *start = ptr;
     const u_char *post_end = end;
@@ -1514,7 +1523,7 @@ static inline int HTTP_CopyExtraDataTosession(const uint8_t *start, int length,
 
 static inline void HTTP_CopyUri(
     HTTPINSPECT_CONF* /*ServerConf*/, const u_char *start, const u_char *end,
-    HttpsessionData *hsd, int stream_ins)
+    HttpSessionData *hsd, int stream_ins)
 {
     int iRet = 0;
     const u_char *cur_ptr;
@@ -1536,7 +1545,7 @@ static inline void HTTP_CopyUri(
 }
 
 
-static inline int unfold_http_uri(HTTPINSPECT_CONF *ServerConf, const u_char *end, URI_PTR *uri_ptr, HttpsessionData *hsd, int stream_ins)
+static inline int unfold_http_uri(HTTPINSPECT_CONF *ServerConf, const u_char *end, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins)
 {
     uint8_t unfold_buf[DECODE_BLEN];
     uint32_t unfold_size =0;
@@ -1576,7 +1585,7 @@ static inline int unfold_http_uri(HTTPINSPECT_CONF *ServerConf, const u_char *en
 static inline int hi_client_extract_uri(
     HI_SESSION *session, HTTPINSPECT_CONF *ServerConf,
     HI_CLIENT * Client, const u_char *start, const u_char *end,
-    const u_char *ptr, URI_PTR *uri_ptr, HttpsessionData *hsd, int stream_ins)
+    const u_char *ptr, URI_PTR *uri_ptr, HttpSessionData *hsd, int stream_ins)
 {
     int iRet = HI_SUCCESS;
     const u_char *tmp;
@@ -1584,7 +1593,6 @@ static inline int hi_client_extract_uri(
 
     session->norm_flags &= ~HI_BODY;
 
-
     /*
     **  This loop compares each char to an array of functions
     **  (one for each char) and calling that function if there is one.
@@ -1714,6 +1722,9 @@ static inline int hi_client_extract_uri(
 
         ptr++;
     }
+    /* No uri in this request. We shouldn't process this request */
+    if(uri_ptr->uri == uri_ptr->uri_end)
+        return HI_NONFATAL_ERR;
     return iRet;
 }
 
@@ -1796,7 +1807,7 @@ const u_char *extract_http_xff(HI_SESSION *session, const u_char *p, const u_cha
     if(!true_ip)
         return p;
 
-    if( (hdrs_args->true_clnt_xff & HDRS_BOTH) == HDRS_BOTH)
+    if( (hdrs_args->true_clnt_xff & (HDRS_BOTH | XFF_HEADERS)) == HDRS_BOTH)
     {
         hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_BOTH_TRUEIP_XFF_HDRS);
     }
@@ -1870,6 +1881,29 @@ const u_char *extract_http_xff(HI_SESSION *session, const u_char *p, const u_cha
                     return p;
                 }
             }
+            /* At this point we have a new/valid IP from the header being processed.
+               If we are using custom xff headers, check the precedence ranking. */
+            if( (hdrs_args->true_clnt_xff & XFF_HEADERS) != 0 )
+            {
+                /* Have we located any others? */
+                if( (hdrs_args->top_precedence > 0) &&
+                    (hdrs_args->new_precedence >= hdrs_args->top_precedence) )
+                    {
+                        sfip_free( tmp );
+                        free( ipAddr );
+                        return( p );
+                    }
+
+                hdrs_args->top_precedence = hdrs_args->new_precedence;
+
+                /* if we find the top precedence, no need to continue
+                   looking so clear the XFF_HEADERS_ACTIVE flag. */
+                if( hdrs_args->top_precedence == XFF_TOP_PRECEDENCE )
+                    hdrs_args->true_clnt_xff &= (~XFF_HEADERS_ACTIVE);
+            }
+
+            /* If we have already set a 'true_ip' for the session, look to see if the
+               new IP differs from the current IP. If so, replace it and post an alert. */
             if(*true_ip)
             {
                 if(!sfip_equals(*true_ip, tmp))
@@ -1877,7 +1911,8 @@ const u_char *extract_http_xff(HI_SESSION *session, const u_char *p, const u_cha
                     sfip_free(*true_ip);
                     *true_ip = tmp;
 
-                    hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_MULTIPLE_TRUEIP_IN_SESSION);
+                    if ((hdrs_args->true_clnt_xff & XFF_HEADERS) == 0)
+                        hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_MULTIPLE_TRUEIP_IN_SESSION);
                 }
                 else
                     sfip_free(tmp);
@@ -1901,7 +1936,7 @@ const u_char *extract_http_xff(HI_SESSION *session, const u_char *p, const u_cha
 
 
 const u_char *extract_http_hostname(HI_SESSION *session, const u_char *p, const u_char *start,
-        const u_char *end, HEADER_PTR *header_ptr, HttpsessionData *hsd)
+        const u_char *end, HEADER_PTR *header_ptr, HttpSessionData *hsd)
 {
     int num_spaces = 0;
     uint8_t unfold_buf[DECODE_BLEN];
@@ -2166,14 +2201,94 @@ const u_char *extract_http_content_length(HI_SESSION *session,
     return p;
 }
 
+static inline bool IsXFFFieldName( HI_CLIENT_HDR_ARGS *hdrs_args,
+                                   u_char **pp, const u_char *end,
+                                   uint8_t **Field_Names, uint8_t *Field_Length )
+{
+    int i;
+    int len;
+    uint8_t *header_ptr;
+    uint8_t *field_ptr;
+
+    i = 0;        // index into the list of XFF field names
+    field_ptr = NULL; // pointer into the active Field_Name entry
+    header_ptr = *pp;  // pointer into the header, will not step past 'end'
+    len = 0;      // len of the matched name entry
+
+    while( true )
+    {
+        /* If we run off the end of the active table, or table is truncated then
+           we can stop.  We didn't locate a match. */
+        if( (i >= (HI_UI_CONFIG_MAX_XFF_FIELD_NAMES)) || (Field_Names[i] == NULL) )
+            break;
+
+        if( field_ptr == NULL )  // didn't start to match any entry
+        {
+            /* If the length doesn't permit a match, move on.  */
+            if( (end - *pp) < Field_Length[i] )
+            {
+                i += 1;
+                continue;
+            }
+
+            if( toupper(*header_ptr) == *Field_Names[i] )  // does the first char match?
+            {
+                /* set our working pointer to the field name */
+                field_ptr = (Field_Names[i] + 1);
+                header_ptr += 1;
+                len = 1;   // We matched one character
+                continue;
+            }
+            i += 1;
+        }
+        else
+        {
+            /* If we are still matching and we get to the end
+               of the field name, then we've located a name match */
+            if( *field_ptr == 0 )  // End of the field name
+            {
+                *pp += len;  // Step input pointer over what we found
+                hdrs_args->new_precedence = (i+1);  // Precedence started with one
+                return( true );
+            }
+            else
+            {
+                /* check for another matching character */
+                if( toupper(*header_ptr) == *field_ptr )
+                {
+                    header_ptr += 1;
+                    field_ptr += 1;
+                    len += 1;
+                }
+                else
+                {
+                    header_ptr = *pp;  // Back to the start for the name
+                    field_ptr = NULL;  // No longer a match
+                    len = 0;
+                    i += 1;
+                }
+            }
+        }
+    }
+
+    return( false );
+}
+
 static inline const u_char *extractHeaderFieldValues(HI_SESSION *session,
         HTTPINSPECT_CONF *ServerConf, const u_char *p, const u_char *offset,
         const u_char *start, const u_char *end, HI_CLIENT_HDR_ARGS *hdrs_args)
 {
-    HttpsessionData *hsd;
+    HttpSessionData *hsd;
 
     hsd = hdrs_args->sd;
-    if (((p - offset) == 0) && ((*p == 'C') || (*p == 'c')))
+    if (((p - offset) == 0) && (ServerConf->enable_xff != 0) &&
+        ((hdrs_args->true_clnt_xff & XFF_HEADERS_ACTIVE) != 0) && (hsd) &&
+        IsXFFFieldName(hdrs_args, (u_char **)&p, (const u_char *)end,
+                       ServerConf->xff_headers, ServerConf->xff_header_lengths))
+    {
+        p = extract_http_xff(session, p, start, end, hdrs_args);
+    }
+    else if (((p - offset) == 0) && ((*p == 'C') || (*p == 'c')))
     {
         /* Search for 'Cookie' at beginning, starting from current *p */
         if ( ServerConf->enable_cookie &&
@@ -2193,7 +2308,8 @@ static inline const u_char *extractHeaderFieldValues(HI_SESSION *session,
     }
     else if (((p - offset) == 0) && ((*p == 'x') || (*p == 'X') || (*p == 't') || (*p == 'T')))
     {
-        if ( (ServerConf->enable_xff) && hsd )
+        //* The default/legacy behavior with two builtin XFF field names */
+        if ( (ServerConf->enable_xff) && hsd && ((hdrs_args->true_clnt_xff & XFF_HEADERS) == 0) )
         {
             if(IsHeaderFieldName(p, end, HEADER_NAME__XFF, HEADER_LENGTH__XFF))
             {
@@ -2274,7 +2390,7 @@ static inline const u_char *extractHeaderFieldValues(HI_SESSION *session,
 static inline const u_char *hi_client_extract_header(
     HI_SESSION *session, HTTPINSPECT_CONF *ServerConf,
     HEADER_PTR *header_ptr, const u_char *start,
-    const u_char *end, HttpsessionData *hsd, int stream_ins)
+    const u_char *end, HttpSessionData *hsd, int stream_ins)
 {
     int iRet = HI_SUCCESS;
     const u_char *p;
@@ -2315,7 +2431,7 @@ static inline const u_char *hi_client_extract_header(
     hdrs_args.sd = hsd;
     hdrs_args.strm_ins = stream_ins;
     hdrs_args.hst_name_hdr = 0;
-    hdrs_args.true_clnt_xff = 0;
+    hdrs_args.true_clnt_xff = (ServerConf->xff_headers[0] != NULL) ? XFF_INIT : 0;
 
     SkipBlankSpace(start,end,&p);
 
@@ -2505,10 +2621,20 @@ static inline const u_char *hi_client_extract_header(
                 Client->request.header_raw = NULL;\
                 Client->request.header_raw_size = 0;\
                 Client->request.header_norm = NULL; \
+                Client->request.header_norm_size = 0 ;\
                 Client->request.cookie.cookie = NULL;\
                 Client->request.cookie.cookie_end = NULL;\
+                if(Client->request.cookie.next) { \
+                    COOKIE_PTR *cookie = Client->request.cookie.next; \
+                    do { \
+                        Client->request.cookie.next = Client->request.cookie.next->next; \
+                        free(cookie); \
+                        cookie = Client->request.cookie.next; \
+                    } while(cookie); \
+                }\
                 Client->request.cookie.next = NULL;\
                 Client->request.cookie_norm = NULL;\
+                Client->request.cookie_norm_size = 0;\
     } while(0);
 
 #define CLR_METHOD(Client) \
@@ -2567,7 +2693,7 @@ static inline const u_char *hi_client_extract_header(
 **  @retval HI_SUCCESS      URI detected and session pointers updated
 */
 
-int StatelessInspection(Packet *p, HI_SESSION *session, HttpsessionData *hsd, int stream_ins)
+int StatelessInspection(Packet *p, HI_SESSION *session, HttpSessionData *hsd, int stream_ins)
 {
     HTTPINSPECT_CONF *ServerConf;
     HTTPINSPECT_CONF *ClientConf;
@@ -2583,7 +2709,7 @@ int StatelessInspection(Packet *p, HI_SESSION *session, HttpsessionData *hsd, in
     const u_char *method_end = NULL;
     int method_len;
     int iRet=0;
-    char sans_uri = 0;
+    bool sans_uri = false;
     const unsigned char *data = p->data;
     int dsize = p->dsize;
 
@@ -2710,19 +2836,19 @@ int StatelessInspection(Packet *p, HI_SESSION *session, HttpsessionData *hsd, in
             if ( !stream_ins )
                 hi_set_event(GID_HTTP_CLIENT, HI_CLIENT_UNKNOWN_METHOD);
             Client->request.method = HI_UNKNOWN_METHOD;
-            sans_uri = 1;
+            sans_uri = true;
         }
     }
 
     if (!sans_uri )
     {
-        uri_ptr.uri = ptr;
+        uri_ptr.uri = method_ptr.uri_end;
         uri_ptr.uri_end = end;
 
         /* This will set up the URI pointers - effectively extracting
          * the URI. */
         iRet = hi_client_extract_uri(
-             session, ServerConf, Client, start, end, ptr, &uri_ptr, hsd, stream_ins);
+             session, ServerConf, Client, start, end, uri_ptr.uri, &uri_ptr, hsd, stream_ins);
     }
 
     /* Check if the URI exceeds the max header field length */
@@ -2880,6 +3006,9 @@ int StatelessInspection(Packet *p, HI_SESSION *session, HttpsessionData *hsd, in
     iRet = SetClientVars(Client, &uri_ptr, dsize);
     if (iRet)
     {
+        CLR_HEADER(Client);
+        CLR_POST(Client);
+        CLR_METHOD(Client);
         return iRet;
     }
     /*
@@ -2910,36 +3039,21 @@ int StatelessInspection(Packet *p, HI_SESSION *session, HttpsessionData *hsd, in
     return HI_SUCCESS;
 }
 
-int hi_client_inspection(Packet *p, void *S, HttpsessionData *hsd, int stream_ins)
+int hi_client_inspection(Packet *p, void *S, HttpSessionData *hsd, int stream_ins)
 {
-    HI_SESSION *session;
-
-    int iRet;
-
     if(!S || !(p->data) || (p->dsize < 1))
     {
         return HI_INVALID_ARG;
     }
 
-    session = (HI_SESSION *)S;
+    HI_SESSION* session = (HI_SESSION*) S;
 
     if(!session->global_conf)
     {
         return HI_INVALID_ARG;
     }
 
-    {
-        /*
-        **  Otherwise we assume stateless inspection
-        */
-        iRet = StatelessInspection(p, session, hsd, stream_ins);
-        if (iRet)
-        {
-            return iRet;
-        }
-    }
-
-    return HI_SUCCESS;
+    return StatelessInspection(p, session, hsd, stream_ins);
 }
 
 /*
@@ -2950,68 +3064,47 @@ int hi_client_inspection(Packet *p, void *S, HttpsessionData *hsd, int stream_in
 **  Initializes arrays and search algorithms depending on the type of
 **  inspection that we are doing.
 **
-**  @param GlobalConf pointer to the global configuration
-**
-**  @return integer
-**
 **  @retval HI_SUCCESS function successful.
 */
-int hi_client_init(HTTPINSPECT_GLOBAL_CONF*)
+int hi_client_init()
 {
     int iCtr;
 
+    memset(lookup_table, 0x00, sizeof(lookup_table));
+
+    // Set up the non-ASCII register for processing.
+    for(iCtr = 0x80; iCtr <= 0xff; iCtr++)
     {
-        memset(lookup_table, 0x00, sizeof(lookup_table));
+        lookup_table[iCtr] = SetBinaryNorm;
+    }
+    lookup_table[0x00] = SetBinaryNorm;
 
-        /*
-        **  Set up the non-ASCII register for processing.
-        */
-        for(iCtr = 0x80; iCtr <= 0xff; iCtr++)
-        {
-            lookup_table[iCtr] = SetBinaryNorm;
-        }
-        lookup_table[0x00] = SetBinaryNorm;
+    lookup_table[(uint8_t)' ']  = NextNonWhiteSpace;
+    lookup_table[(uint8_t)'\r'] = find_rfc_delimiter;
+    lookup_table[(uint8_t)'\n'] = find_non_rfc_delimiter;
 
-        lookup_table[(uint8_t)' ']  = NextNonWhiteSpace;
-        lookup_table[(uint8_t)'\r'] = find_rfc_delimiter;
-        lookup_table[(uint8_t)'\n'] = find_non_rfc_delimiter;
+    // ASCII encoding
+    lookup_table[(uint8_t)'%']  = SetPercentNorm;
 
-        /*
-        **  ASCII encoding
-        */
-        lookup_table[(uint8_t)'%']  = SetPercentNorm;
+    // Looking for multiple slashes
+    lookup_table[(uint8_t)'/']  = SetSlashNorm;
 
-        /*
-        **  Looking for multiple slashes
-        */
-        lookup_table[(uint8_t)'/']  = SetSlashNorm;
+    // Looking for backslashs
+    lookup_table[(uint8_t)'\\'] = SetBackSlashNorm;
 
-        /*
-        **  Looking for backslashs
-        */
-        lookup_table[(uint8_t)'\\'] = SetBackSlashNorm;
-
-        lookup_table[(uint8_t)'+'] = SetPlusNorm;
-
-
-        /*
-        **  Look up parameter field, so we don't alert on long directory
-        **  strings, when the next slash in the parameter field.
-        */
-        lookup_table[(uint8_t)'?'] = SetParamField;
+    lookup_table[(uint8_t)'+'] = SetPlusNorm;
 
-        /*
-        **  Look for absolute URI and proxy communication.
-        */
-        lookup_table[(uint8_t)':'] = SetProxy;
+    //  Look up parameter field, so we don't alert on long directory
+    //  strings, when the next slash in the parameter field.
+    lookup_table[(uint8_t)'?'] = SetParamField;
 
-    }
+    //  Look for absolute URI and proxy communication.
+    lookup_table[(uint8_t)':'] = SetProxy;
 
     return HI_SUCCESS;
 }
 
 
-
 /**
 **  This was just an initial testing program for these functions.
 */
@@ -3040,7 +3133,7 @@ int main(int argc, char **argv)
 
     hi_ui_config_print_config(&GlobalConf);
 
-    if((iRet = hi_client_init(&GlobalConf)))
+    if((iRet = hi_client_init()))
     {
         printf("** error client init\n");
         return iRet;
index 70e248f413707cd3300ef1023d06307003ffa4db..842e678cd33cc7b331f94db11e4e55d40ec246b0 100644 (file)
 #define URI_END  99
 #define POST_END 100
 #define NO_URI   101
-typedef enum {
-    TRUE_CLIENT_IP_HDR = 0x01,
-    XFF_HDR = 0x02,
-    HDRS_BOTH = 0x03
-} ActionSFCC;
 
+#define XFF_MODE_MASK      (0x000f)
+#define XFF_EXFF_MASK      (0x000c)
 
+#define TRUE_CLIENT_IP_HDR (0x01)
+#define XFF_HDR            (0x02)
+#define HDRS_BOTH          (0x03)
+#define XFF_HEADERS        (0x04)  // Using xff_headers list
+#define XFF_HEADERS_ACTIVE (0x08)  // Looking for highest precedence xff header
+#define XFF_INIT (XFF_HEADERS | XFF_HEADERS_ACTIVE)
+
+#define XFF_TOP_PRECEDENCE (1)
+#define XFF_BOT_PRECEDENCE (255)
 typedef struct s_COOKIE_PTR
 {
     const u_char *cookie;
@@ -116,11 +123,6 @@ typedef struct s_HEADER_PTR
 
 typedef struct s_HI_CLIENT_REQ
 {
-    /*
-    u_char *method;
-    int  method_size;
-    */
-
     const u_char *uri;
     const u_char *uri_norm;
     const u_char *post_raw;
@@ -140,23 +142,6 @@ typedef struct s_HI_CLIENT_REQ
     u_int cookie_norm_size;
     u_int method_size;
 
-    /*
-    u_char *param;
-    u_int  param_size;
-    u_int  param_norm;
-    */
-
-    /*
-    u_char *ver;
-    u_int  ver_size;
-
-    u_char *hdr;
-    u_int  hdr_size;
-
-    u_char *payload;
-    u_int  payload_size;
-    */
-
     const u_char *pipeline_req;
     u_char method;
     uint16_t uri_encode_type;
@@ -178,14 +163,18 @@ typedef struct s_HI_CLIENT_HDR_ARGS
 {
     HEADER_PTR *hdr_ptr;
     HEADER_FIELD_PTR *hdr_field_ptr;
-    HttpsessionData *sd; 
+    HttpSessionData *sd; 
     int strm_ins; 
     int hst_name_hdr;
-    int true_clnt_xff;
+    uint8_t true_clnt_xff;
+    uint8_t top_precedence;
+    uint8_t new_precedence;
 } HI_CLIENT_HDR_ARGS;
 
-int hi_client_inspection(Packet *p, void *session, HttpsessionData *hsd, int stream_ins);
-int hi_client_init(HTTPINSPECT_GLOBAL_CONF *GlobalConf);
+int hi_client_inspection(Packet *p, void *session, HttpSessionData *hsd, int stream_ins);
+int hi_client_init();
+
+char **hi_client_get_field_names();
 
 extern const u_char *proxy_start;
 extern const u_char *proxy_end;
diff --git a/src/service_inspectors/http_inspect/hi_client_stateful.h b/src/service_inspectors/http_inspect/hi_client_stateful.h
deleted file mode 100644 (file)
index 250d01f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2005-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-/*
-*  hi_client_stateful.h: Functions prototypes for client
- *             stateful processing.
-*  
-*  Author: Chris Sherwin <csherwin@sourcefire.com>
-*
-*/
-#ifndef HI_CLIENT_STATEFUL_H
-#define HI_CLIENT_STATEFUL_H
-
-#include "hi_include.h"
-#include "hi_si.h"
-
-int StatefulInspection( HI_SESSION* sessionp, unsigned char* datap, int dsize );
-
-#endif /* HI_CLIENT_STATEFUL_H */
index 67422ce90cef4f1263f0afa00d4e66adc251c9cb..2ed704844aee2447466d74585da80db97009497a 100644 (file)
@@ -81,8 +81,14 @@ typedef enum _HI_EVENTS
     HI_SERVER_JS_OBFUSCATION_EXCD,
     HI_SERVER_JS_EXCESS_WS,
     HI_SERVER_MIXED_ENCODINGS,
+    HI_SERVER_SWF_ZLIB_FAILURE,
+    HI_SERVER_SWF_LZMA_FAILURE,
+    HI_SERVER_PDF_DEFL_FAILURE,
+    HI_SERVER_PDF_UNSUP_COMP_TYPE,
+    HI_SERVER_PDF_CASC_COMP,
+    HI_SERVER_PDF_PARSE_FAILURE,
     HI_SERVER_EVENT_NUM
-}HI_EVENTS;
+} HI_EVENTS;
 
 /*
 **  These defines are the alert names for each event
@@ -183,6 +189,18 @@ typedef enum _HI_EVENTS
     "javascript whitespaces exceeds max allowed"
 #define HI_SERVER_MIXED_ENCODINGS_STR                \
     "multiple encodings within javascript obfuscated data"
+#define HI_SERVER_SWF_ZLIB_FAILURE_STR               \
+    "HTTP response SWF file zlib decompression failure"
+#define HI_SERVER_SWF_LZMA_FAILURE_STR               \
+    "HTTP response SWF file LZMA decompression failure"
+#define HI_SERVER_PDF_DEFL_FAILURE_STR               \
+    "HTTP response PDF file deflate decompression failure"
+#define HI_SERVER_PDF_UNSUP_COMP_TYPE_STR            \
+    "HTTP response PDF file unsupported compression type"
+#define HI_SERVER_PDF_CASC_COMP_STR                  \
+    "HTTP response PDF file cascaded compression"
+#define HI_SERVER_PDF_PARSE_FAILURE_STR              \
+    "HTTP response PDF file parse failure"
 
 void hi_set_event(unsigned gid, unsigned sid);
 void hi_clear_events();
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp.cc b/src/service_inspectors/http_inspect/hi_file_decomp.cc
new file mode 100644 (file)
index 0000000..b6a9eda
--- /dev/null
@@ -0,0 +1,417 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "util.h"
+#include "hi_file_decomp.h"
+#include "snort_types.h"
+#include "detection_util.h"
+#include "hi_file_decomp_pdf.h"
+#include "hi_file_decomp_swf.h"
+
+static const char PDF_Sig[5] = { '%', 'P', 'D', 'F', '-' };
+static const char SWF_ZLIB_Sig[3] = { 'C', 'W', 'S' };
+#ifdef LZMA
+static const char SWF_LZMA_Sig[3] = { 'Z', 'W', 'S' };
+#endif
+static const char SWF_Uncomp_Sig[3] = { 'F', 'W', 'S' };
+
+/* Please assure that the following value correlates with the set of sig's */
+#define MAX_SIG_LENGTH (5)
+
+static struct sig_map_s
+{
+    const char* Sig;
+    size_t Sig_Length;
+    bool Enabled;
+    file_type_t File_Type;
+    file_compression_type_t File_Compression_Type;
+} Signature_Map[] =
+{
+
+    { PDF_Sig, sizeof(PDF_Sig), false, FILE_TYPE_PDF, FILE_COMPRESSION_TYPE_NONE },  // Compression type is embedded in PDF dictionaries
+    { SWF_ZLIB_Sig, sizeof(SWF_ZLIB_Sig), false, FILE_TYPE_SWF, FILE_COMPRESSION_TYPE_ZLIB },
+#ifdef LZMA
+    { SWF_LZMA_Sig, sizeof(SWF_LZMA_Sig), false, FILE_TYPE_SWF, FILE_COMPRESSION_TYPE_LZMA },
+#endif
+    { NULL, 0, false, FILE_TYPE_NONE, FILE_COMPRESSION_TYPE_NONE }
+};
+
+/* Define the elements of the Sig_State value (packed for storage efficiency */
+#define SIG_MATCH_ACTIVE    (0x80)
+#define SIG_SIG_INDEX_MASK  (0x70)
+#define SIG_SIG_INDEX_SHIFT (4)
+#define SIG_CHR_INDEX_MASK  (0x07)
+#define SIG_CHR_INDEX_SHIFT (0)
+
+static uint8_t File_Decomp_Buffer[DECODE_BLEN];
+
+/* Look for possible sig at the current payload location.
+   Do NOT beyond the current location (initial Next_In). */
+static fd_status_t Locate_Sig_Here( fd_session_p_t SessionPtr )
+{
+    uint64_t Sig_Index, Char_Index;
+
+    /* If there's no new input, we don't change state */
+    if( (SessionPtr->Avail_In == 0) ||
+        (SessionPtr->Next_In == NULL) || (SessionPtr->Next_Out == NULL) )
+        return( File_Decomp_Error );
+
+    if( SessionPtr->Avail_Out < MAX_SIG_LENGTH )
+        return( File_Decomp_BlockOut );
+
+    /* Given that we are here, there is at least one input byte to process.
+       And at least enough room in the output stream for the signature. */
+
+   /* Have we started down a sig string? */
+    if( (SessionPtr->Sig_State & SIG_MATCH_ACTIVE) != 0 )
+    {
+        /* Get the current index into the sig map table (indicating which sig) and
+           the index into the sig itself.  */
+        Sig_Index = (SessionPtr->Sig_State & SIG_SIG_INDEX_MASK) >> SIG_SIG_INDEX_SHIFT;
+        /* Char_Index indicates the sig char that we are looking for now. */
+        Char_Index = (SessionPtr->Sig_State & SIG_CHR_INDEX_MASK) >> SIG_CHR_INDEX_SHIFT;
+    }
+    else
+    {
+        Sig_Index = 0;
+        Char_Index = 0;
+    }
+
+    /* There must be more in the input stream for us to look at, else
+       we indicate that we didn't find the sig yet. */
+    if( SessionPtr->Avail_In <= Char_Index )
+        return( File_Decomp_BlockIn );
+
+    /* NOTE:  The following code block makes the assumption that there are
+              at least MAX_SIG_LENGTH bytes in the output buffer.  This assumption 
+              is valid for the current implementation where the signature only
+              occurs at the beginning of the file.  For the generic case of the sig
+              begin embedded with the file, the seach will need to modified.*/
+    while( 1 )
+    {
+        /* if we get to the end of the sig table (or the table is empty),
+           indicate that we didn't match a sig */
+        if( Signature_Map[Sig_Index].Sig == NULL )
+            return( File_Decomp_NoSig );
+
+        /* Get next char and see if it matches next char in sig */
+        if( (Signature_Map[Sig_Index].Enabled) &&
+            (*(SessionPtr->Next_In+Char_Index) == *(Signature_Map[Sig_Index].Sig+Char_Index)) )
+        { 
+            /* Check to see if we are at the end of the sig string. */
+            if( Char_Index == (Signature_Map[Sig_Index].Sig_Length-1) )
+            {
+                uint8_t *Sig = (uint8_t *)Signature_Map[Sig_Index].Sig;
+                uint16_t Len = (uint16_t)Signature_Map[Sig_Index].Sig_Length;
+
+                SessionPtr->File_Type = Signature_Map[Sig_Index].File_Type;
+                SessionPtr->Decomp_Type = Signature_Map[Sig_Index].File_Compression_Type;
+
+                if( (SessionPtr->File_Type == FILE_TYPE_SWF) && ((SessionPtr->Modes & FILE_REVERT_BIT) != 0) )
+                {
+                    Sig = (uint8_t *)SWF_Uncomp_Sig;
+                    Len = (uint16_t)sizeof( SWF_Uncomp_Sig );
+                }
+                /* The following is safe as we can only be here is there are
+                   are least MAX_SIG_LENGTH bytes in the output buffer */
+                (void)Put_N(SessionPtr, Sig, Len);
+                /* Skip the Sig bytes in the input stream */
+                SessionPtr->Next_In += Len;
+                SessionPtr->Avail_In -= Len;
+                SessionPtr->Total_In += Len;
+                return( File_Decomp_OK );
+            }
+                
+            /* check for more available input bytes */
+            if( Char_Index < SessionPtr->Avail_In )
+            {
+                /* Set to the next char and keep checking this matching sig */
+                Char_Index += 1;
+                continue; /* goto top of while() loop */
+            }
+            else
+            {
+                /* Indicate that we are actively finding a sig, save the char index
+                   and save the sig index.  We'll pickup where we left off when more
+                   input is available. */
+                SessionPtr->Sig_State = SIG_MATCH_ACTIVE |
+                                       ((Sig_Index & SIG_SIG_INDEX_MASK) << SIG_SIG_INDEX_SHIFT) |
+                                       ((Char_Index & SIG_CHR_INDEX_MASK) << SIG_CHR_INDEX_SHIFT);
+                return( File_Decomp_BlockIn );
+            }
+        }
+        else
+        {
+            /* Failed somewhere matching this sig, goto next sig and reset the
+               Char_Index to the beginning */
+            Sig_Index += 1;
+            Char_Index = 0;
+        }
+    }
+}
+
+static fd_status_t Initialize_Decompression( fd_session_p_t SessionPtr )
+{
+    fd_status_t Ret_Code = File_Decomp_OK;
+
+    switch( SessionPtr->File_Type )
+    {
+        case( FILE_TYPE_SWF ):
+        {
+            Ret_Code = File_Decomp_Init_SWF( SessionPtr );
+            break;
+        }
+        case( FILE_TYPE_PDF ):
+        {
+            Ret_Code = File_Decomp_Init_PDF( SessionPtr );
+            break;
+        }
+        default:
+           return( File_Decomp_Error );
+    }
+
+    if( Ret_Code == File_Decomp_OK )
+        SessionPtr->State = STATE_ACTIVE;
+
+    return( Ret_Code );
+}
+
+static fd_status_t Process_Decompression( fd_session_p_t SessionPtr )
+{
+    fd_status_t Ret_Code = File_Decomp_OK;
+
+    switch( SessionPtr->File_Type )
+    {
+        case( FILE_TYPE_SWF ):
+        {
+            Ret_Code = File_Decomp_SWF( SessionPtr );
+            break;
+        }
+        case( FILE_TYPE_PDF ):
+        {
+            Ret_Code = File_Decomp_PDF( SessionPtr );
+            break;
+        }
+        default:
+           return( File_Decomp_Error );
+    }
+
+    if( Ret_Code == File_Decomp_Complete )
+        SessionPtr->State = STATE_COMPLETE;
+
+    return( Ret_Code );
+}
+
+/* The caller provides Compr_Depth, Decompr_Depth and Modes in the session object.
+   Based on the requested Modes, gear=up to initialize the potential decompressors. */
+fd_status_t File_Decomp_Init( fd_session_p_t SessionPtr )
+{
+    int Sig;
+
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    SessionPtr->State = STATE_READY;
+    SessionPtr->File_Type = FILE_TYPE_NONE;
+    SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+
+    for( Sig=0; Signature_Map[Sig].Sig != NULL; Sig++ )
+    {
+        if( (Signature_Map[Sig].File_Type == FILE_TYPE_PDF ) &&
+            ((SessionPtr->Modes & FILE_PDF_ANY) != 0) )
+            Signature_Map[Sig].Enabled = true;
+
+        if( (Signature_Map[Sig].File_Type == FILE_TYPE_SWF ) &&
+            (Signature_Map[Sig].File_Compression_Type == FILE_COMPRESSION_TYPE_ZLIB) &&
+            ((SessionPtr->Modes & FILE_SWF_ZLIB_BIT) != 0) )
+            Signature_Map[Sig].Enabled = true;
+#ifdef LZMA
+        if( (Signature_Map[Sig].File_Type == FILE_TYPE_SWF ) &&
+            (Signature_Map[Sig].File_Compression_Type == FILE_COMPRESSION_TYPE_LZMA) &&
+            ((SessionPtr->Modes & FILE_SWF_LZMA_BIT) != 0) )
+            Signature_Map[Sig].Enabled = true;
+#endif 
+    }
+
+    return( File_Decomp_OK );
+}
+
+/* Setup session to use internal decompression buffer. Set compr/decompr limits */
+fd_status_t File_Decomp_SetBuf( fd_session_p_t SessionPtr )
+{
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    SessionPtr->Buffer = File_Decomp_Buffer;
+    SessionPtr->Buffer_Len = sizeof(File_Decomp_Buffer);
+
+    SessionPtr->Next_Out = File_Decomp_Buffer;
+    SessionPtr->Avail_Out = sizeof(File_Decomp_Buffer);
+
+    /* If Compr/Decompr limits are set, then enforce then. */
+    if( SessionPtr->Decompr_Depth > 0 )
+    {
+        uint32_t remainder;
+
+        if( SessionPtr->Total_Out > SessionPtr->Decompr_Depth )
+            return( File_Decomp_Error );
+
+        /* Calc whats left in allowance */
+        remainder = (SessionPtr->Total_Out - SessionPtr->Decompr_Depth);
+
+        /* Use smaller of remainder or value provided */
+        SessionPtr->Avail_Out = (remainder < SessionPtr->Avail_Out) ?
+                                 remainder : SessionPtr->Avail_Out;
+    }
+
+    if( SessionPtr->Compr_Depth > 0 )
+    {
+        uint32_t remainder;
+
+        if( SessionPtr->Total_In > SessionPtr->Compr_Depth )
+            return( File_Decomp_Error );
+
+        remainder = (SessionPtr->Total_In - SessionPtr->Compr_Depth);
+
+        SessionPtr->Avail_In = (remainder < SessionPtr->Avail_In) ?
+                                remainder : SessionPtr->Avail_In;
+    }
+
+    /* SessionPtr->Next_In is set by the caller to File_Decomp() */
+
+    return( File_Decomp_OK );
+}
+
+/* Returns a new session object from the MemPool */
+fd_session_p_t File_Decomp_New()
+{
+    fd_session_p_t New_Session = new fd_session_t;
+
+    New_Session->State = STATE_NEW;
+    New_Session->Sig_State = 0;
+    New_Session->Total_In = 0;
+    New_Session->Total_Out = 0;
+    New_Session->Avail_In = 0;
+    New_Session->Next_In = NULL;
+    New_Session->Avail_Out = 0;
+    New_Session->Next_Out = NULL;
+
+    return New_Session;
+}
+
+/* Process Decompression.  The session Next_In, Avail_In, Next_Out, Avail_Out MUST have been
+   set by caller. 
+*/
+fd_status_t File_Decomp( fd_session_p_t SessionPtr )
+{
+    fd_status_t Return_Code;
+
+    if( (SessionPtr->State == STATE_NEW) ||
+        (SessionPtr->Next_In == NULL) || (SessionPtr->Next_Out == NULL) )
+        return( File_Decomp_Error );
+
+    /* STATE_NEW: Look for one of the configured file signatures. */
+    if( SessionPtr->State == STATE_READY )
+    {
+        /* Look for the signature at the beginning of the payload stream. */
+        if( (Return_Code = Locate_Sig_Here( SessionPtr )) == File_Decomp_OK )
+        {
+            /* We now know the file type and decompression type.  Setup appropriate state. */
+            if( (Return_Code = Initialize_Decompression( SessionPtr )) == File_Decomp_OK )
+            {
+                return( Process_Decompression( SessionPtr ) );
+            }
+            else
+                return( Return_Code );
+        }
+        else
+            /* Locate_Sig_Here() might return BlockIn, BlockOut, Error, or NoSig */
+            return( Return_Code );
+    }
+    else if( SessionPtr->State == STATE_ACTIVE )
+    {
+        return( Process_Decompression( SessionPtr ) );
+    }
+    else
+        return( File_Decomp_Error );
+}
+
+
+fd_status_t File_Decomp_End( fd_session_p_t SessionPtr )
+{
+    if( SessionPtr == NULL ) 
+        return( File_Decomp_Error );
+
+    switch( SessionPtr->File_Type )
+    {
+        case( FILE_TYPE_SWF ):
+        {
+            return( File_Decomp_End_SWF( SessionPtr ) );
+        }
+        case( FILE_TYPE_PDF ):
+        {
+            return( File_Decomp_End_PDF( SessionPtr ) );
+        }
+        default:
+           return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+fd_status_t File_Decomp_Reset( fd_session_p_t SessionPtr )
+{
+    fd_status_t Ret_Code;
+
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    Ret_Code = File_Decomp_End( SessionPtr );
+
+    SessionPtr->State = STATE_READY;
+
+    return( Ret_Code );
+}
+
+fd_status_t File_Decomp_StopFree( fd_session_p_t SessionPtr )
+{
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    File_Decomp_End( SessionPtr );
+    File_Decomp_Free( SessionPtr );
+
+    return( File_Decomp_OK );
+}
+
+
+void File_Decomp_Free( fd_session_p_t SessionPtr )
+{
+    delete SessionPtr;
+}
+
+void File_Decomp_Alert( fd_session_p_t SessionPtr, int Event )
+{
+    if( (SessionPtr != NULL) && (SessionPtr->Alert_Callback != NULL) && (SessionPtr->Alert_Context) )
+        (SessionPtr->Alert_Callback)(SessionPtr->Alert_Context, Event);
+}
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp.h b/src/service_inspectors/http_inspect/hi_file_decomp.h
new file mode 100644 (file)
index 0000000..ea35dc4
--- /dev/null
@@ -0,0 +1,272 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifndef HI_FILE_DECOMP_H
+#define HI_FILE_DECOMP_H
+
+// FIXIT-H temporary for development convenience
+//#define LZMA 1
+
+#include <stdint.h>
+#include <string.h>
+
+/* File_Decomp global typedefs (used in child objects) */
+typedef enum fd_status
+{
+    File_Decomp_DecompError = -2,  /* Error from decompression */
+    File_Decomp_Error = -1,        /* Error from decompression */
+    File_Decomp_OK = 0,
+    File_Decomp_NoSig = 1,         /* No file signature located */
+    File_Decomp_Complete = 2,      /* Completed */
+    File_Decomp_BlockOut = 3,      /* Blocked due to lack of output space */
+    File_Decomp_BlockIn = 4,       /* Blocked due to lack in input data */
+    File_Decomp_Eof = 5            /* End of file located */
+} fd_status_t;
+
+typedef enum file_compression_type
+{
+    FILE_COMPRESSION_TYPE_NONE,
+    FILE_COMPRESSION_TYPE_DEFLATE,
+    FILE_COMPRESSION_TYPE_ZLIB,
+    FILE_COMPRESSION_TYPE_LZMA,
+    FILE_COMPRESSION_TYPE_MAX
+} file_compression_type_t;
+
+typedef struct fd_session_s *fd_session_p_t, fd_session_t;
+
+#include "hi_file_decomp_pdf.h"
+#include "hi_file_decomp_swf.h"
+#include <zlib.h>
+
+#ifdef LZMA
+#include <lzma.h>
+#endif
+
+/* Potential decompression modes */
+#define FILE_SWF_LZMA_BIT    (0x00000001)
+#define FILE_SWF_ZLIB_BIT    (0x00000002)
+#define FILE_PDF_DEFL_BIT    (0x00000004)
+#define FILE_FILT_NORM_BIT   (0x40000000)    /* Normalize the PDF /Filter value string */
+#define FILE_REVERT_BIT      (0x80000000)    /* Revert to 'uncompressed' state */
+
+#define FILE_PDF_ANY         (FILE_PDF_DEFL_BIT)
+#define FILE_SWF_ANY         (FILE_SWF_LZMA_BIT | FILE_SWF_ZLIB_BIT)
+
+/* Private Types */
+typedef enum file_type
+{
+    FILE_TYPE_NONE,
+    FILE_TYPE_SWF,
+    FILE_TYPE_PDF,
+    FILE_TYPE_MAX
+} file_type_t;
+
+typedef enum states
+{
+    STATE_NEW,        /* Session created */
+    STATE_READY,      /* Session created and ready for content, no file/decomp selected */
+    STATE_ACTIVE,     /* Decompressor inited and ready for content */
+    STATE_COMPLETE    /* Decompression completed */
+} fd_states_t;
+
+struct fd_session_s
+{
+    uint8_t *Next_In;   /* next input byte */
+    uint32_t Avail_In;  /* number of bytes available at next_in */
+    uint32_t Total_In;  /* total number of input bytes read so far */
+
+    uint8_t *Next_Out;  /* next output byte should be put there */
+    uint32_t Avail_Out; /* remaining free space at next_out */
+    uint32_t Total_Out; /* total number of bytes output so far */
+
+    /* Internal buffer setup by _Init().  App can overide. */
+    uint8_t *Buffer;    /* pointer to decompresiion buffer */
+    uint32_t Buffer_Len;/* length of decompression buffer */
+
+    /* Configuration settings */
+    uint32_t Compr_Depth;
+    uint32_t Decompr_Depth;
+    uint32_t Modes;     /* Bit mapped set of potential file/algo modes */
+
+    /* Alerting callback */
+    void (*Alert_Callback)(void *Context, int Event);
+    void *Alert_Context;
+
+    /* Internal State */
+    uint8_t File_Type;   /* Active file type */
+    uint8_t Decomp_Type; /* Active decompression type */
+    uint8_t Sig_State;   /* Sig search state machine */
+    uint8_t State;       /* main state machine */
+
+    union
+    {
+        fd_PDF_t PDF;
+        fd_SWF_t SWF;
+    } Decomp_State;
+
+    /* Specific event indicated by DecomprError return */
+    int Error_Event;
+};
+
+/* Macros */
+
+#ifndef SYNC_IN
+#define SYNC_IN(dest) \
+    dest->next_in = SessionPtr->Next_In; \
+    dest->avail_in = SessionPtr->Avail_In; \
+    dest->total_in = SessionPtr->Total_In; \
+    dest->next_out = SessionPtr->Next_Out; \
+    dest->avail_out = SessionPtr->Avail_Out; \
+    dest->total_out = SessionPtr->Total_Out;
+#endif
+
+#ifndef SYNC_OUT
+#define SYNC_OUT(src) \
+    SessionPtr->Next_In = (uint8_t *)src->next_in; \
+    SessionPtr->Avail_In = src->avail_in; \
+    SessionPtr->Total_In = src->total_in; \
+    SessionPtr->Next_Out = (uint8_t *)src->next_out; \
+    SessionPtr->Avail_Out = src->avail_out; \
+    SessionPtr->Total_Out = src->total_out;
+#endif
+
+
+/* Inline Functions */
+
+static inline bool Peek_1( fd_session_p_t SessionPtr, uint8_t *c)
+{
+    if( (SessionPtr->Next_In != NULL) && (SessionPtr->Avail_In > 0) )
+    {
+        *c = *(SessionPtr->Next_In);
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Get_1( fd_session_p_t SessionPtr, uint8_t *c )
+{
+    if( (SessionPtr->Next_In != NULL) && (SessionPtr->Avail_In > 0) )
+    {
+        *c = *(SessionPtr->Next_In)++;
+        SessionPtr->Avail_In -= 1;
+        SessionPtr->Total_In += 1;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Get_N( fd_session_p_t SessionPtr, uint8_t **c, uint16_t N )
+{
+    if( (SessionPtr->Next_In != NULL) && (SessionPtr->Avail_In >= N) )
+    {
+        *c = SessionPtr->Next_In;
+        SessionPtr->Next_In += N;
+        SessionPtr->Avail_In -= N;
+        SessionPtr->Total_In += N;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Put_1( fd_session_p_t SessionPtr, uint8_t c )
+{
+    if( (SessionPtr->Next_Out != NULL) && (SessionPtr->Avail_Out > 0) )
+    {
+        *(SessionPtr->Next_Out)++ = c;
+        SessionPtr->Avail_Out -= 1;
+        SessionPtr->Total_Out += 1;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Put_N( fd_session_p_t SessionPtr, uint8_t *c, uint16_t N )
+{
+    if( (SessionPtr->Next_Out != NULL) && (SessionPtr->Avail_Out >= N) )
+    {
+        strncpy( (char *)SessionPtr->Next_Out, (const char *)c, N);
+        SessionPtr->Next_Out += N;
+        SessionPtr->Avail_Out -= N;
+        SessionPtr->Total_Out += N;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Move_1( fd_session_p_t SessionPtr )
+{
+    if( (SessionPtr->Next_Out != NULL) && (SessionPtr->Avail_Out > 0) &&
+        (SessionPtr->Next_In != NULL) && (SessionPtr->Avail_In > 0) )
+    {
+        *(SessionPtr->Next_Out) = *(SessionPtr->Next_In);
+        SessionPtr->Next_Out += 1;
+        SessionPtr->Next_In += 1;
+        SessionPtr->Avail_In -= 1;
+        SessionPtr->Avail_Out -= 1;
+        SessionPtr->Total_In += 1;
+        SessionPtr->Total_Out += 1;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+static inline bool Move_N( fd_session_p_t SessionPtr, uint16_t N )
+{
+    if( (SessionPtr->Next_Out != NULL) && (SessionPtr->Avail_Out >= N) && 
+        (SessionPtr->Next_In != NULL) && (SessionPtr->Avail_In >= N) )
+    {
+        strncpy( (char *)SessionPtr->Next_Out, (const char *)SessionPtr->Next_In, N);
+        SessionPtr->Next_Out += N;
+        SessionPtr->Next_In += N;
+        SessionPtr->Avail_In -= N;
+        SessionPtr->Avail_Out -= N;
+        SessionPtr->Avail_Out -= N;
+        SessionPtr->Total_Out += N;
+        return( true );
+    }
+    else
+        return( false );
+}
+
+/* API Functions */
+
+fd_session_p_t File_Decomp_New();
+
+fd_status_t File_Decomp_Init( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_SetBuf( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_End( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_Reset( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_StopFree( fd_session_p_t SessionPtr );
+
+void File_Decomp_Free( fd_session_p_t SessionPtr );
+
+void File_Decomp_Alert( fd_session_p_t SessionPtr, int Event );
+#endif
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp_pdf.cc b/src/service_inspectors/http_inspect/hi_file_decomp_pdf.cc
new file mode 100644 (file)
index 0000000..f80cebd
--- /dev/null
@@ -0,0 +1,1151 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <zlib.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "hi_file_decomp.h"
+#include "hi_file_decomp_pdf.h"
+#include "hi_events.h"
+#include "mstring.h"
+
+/* Define characters and tokens in PDF grammar */
+#define TOK_STRM_OPEN      "stream"
+#define TOK_STRM_CLOSE     "endstream"
+
+#define TOK_OBJ_OPEN       "obj"
+#define TOK_OBJ_CLOSE      "endobj"
+
+#define TOK_DICT_OPEN      "<<"
+#define TOK_DICT_CLOSE     ">>"
+#define TOK_DICT_FILT      "Filter"
+#define TOK_DICT_FLATE     "FlateDecode"
+#define TOK_DICT_FLATE_ALT "Fl"
+#define TOK_DICT_PARMS     "DecodeParms"
+#define TOK_DICT_PARMS_ALT "DP"
+#define TOK_DICT_LENGTH    "Length"
+#define TOK_DICT_NULL      "null"
+#define TOK_DICT_NULL_FILT " null "  // Enclose the null object in spaces
+#define TOK_XRF_XREF       "xref"
+#define TOK_XRF_TRAILER    "trailer"
+#define TOK_XRF_STARTXREF  "startxref"
+#define TOK_XRF_END        "%%EOF"
+
+#define WHITESPACE_STRING  "\011\012\014\015\040" // plus \000
+
+#define TOK_EOL_CR         "\r"
+#define TOK_EOL_LF         "\n"
+#define TOK_EOL_CRLF       "\r\n"
+
+#define CHR_CR             '\r'
+#define CHR_LF             '\n'
+
+#define CHR_COMMENT        '%'
+
+#define CHR_ARRAY_OPEN     '['
+#define CHR_ARRAY_CLOSE    ']'
+
+#define CHR_ANGLE_OPEN     '<'
+#define CHR_ANGLE_CLOSE    '>'
+
+#define CHR_SPACE          ' '
+#define CHR_NAME_SEP       '/'
+
+#define IS_WHITESPACE(c) ((strchr((char *)WHITESPACE_STRING, (int)c) != NULL) || (c == 0))
+#define IS_EOL(c) ((c == CHR_CR) || (c == CHR_LF))
+
+/* Define the parser states */
+typedef enum p_states
+{
+    P_START = 1,    // Ground state, nothing 'open'
+    P_COMMENT,      // inside a comment (initial state of parser)
+    P_IND_OBJ,      // Indirect Object - Sub_State usage
+    P_XREF,         // The combined xref, trailer, startxref top level items
+    P_DICT_OBJECT,  // A dictionary object
+    P_STREAM        // A pseudo state used to process a stream object
+} p_state_t;
+
+typedef enum p_xref_substates
+{
+    P_XREF_TOKEN = 1,
+    P_XREF_END_TOKEN
+} p_xref_t;
+
+typedef enum p_dict_substates
+{
+    P_DICT_OPEN = 1,
+    P_DICT_OPEN_TOK,
+    P_DICT_CLOSE_TOK,
+    P_DICT_FILTER,
+    P_DICT_SKIP,
+    P_DICT_ACTIVE
+} p_dict_t;
+
+typedef enum p_indirect_object_substates
+{
+    P_OBJ_NUMBER = 1,
+    P_GEN_NUMBER,
+    P_OBJ_TOKEN,
+    P_OBJ_EOL,
+    P_STREAM_TOKEN,
+    P_STREAM_EOL,
+    P_STREAM_LF,
+    P_ENDSTREAM_TOKEN,
+    P_ENDOBJ_TOKEN
+} p_indirect_object_substate_t;
+
+static struct filters_s
+{
+    const char *Token;
+    uint8_t Length;
+    uint8_t Type;
+} Filter_Map[] =
+{
+    { TOK_DICT_FLATE, (sizeof(TOK_DICT_FLATE)-1), FILE_COMPRESSION_TYPE_DEFLATE },
+    { TOK_DICT_FLATE_ALT, (sizeof(TOK_DICT_FLATE_ALT)-1), FILE_COMPRESSION_TYPE_DEFLATE },
+    { TOK_DICT_NULL, (sizeof(TOK_DICT_NULL)-1), FILE_COMPRESSION_TYPE_NONE },
+    { NULL, 0, FILE_COMPRESSION_TYPE_NONE }
+};
+
+/* Given a pointer to a /Filter value token, return the
+   associated compression type from the Filter_Map. */
+static inline uint8_t Get_Decomp_Type( uint8_t *Token, uint8_t Length )
+{
+    int Index;
+
+    Index=0;
+
+    while( Filter_Map[Index].Token != NULL )
+    {
+        if( (Filter_Map[Index].Length == Length) &&
+            (strncmp( (const char *)Token, Filter_Map[Index].Token, Length ) == 0 ) )
+            return( Filter_Map[Index].Type );
+        else
+            Index += 1;
+    }
+    return( FILE_COMPRESSION_TYPE_NONE );
+}
+
+static inline void Process_One_Filter( fd_session_p_t SessionPtr, uint8_t *Token, uint8_t Length )
+{
+    uint8_t Comp_Type;
+
+    /* Lookup the token and see if it matches a known filter */
+    Comp_Type = Get_Decomp_Type( Token, Length );
+
+    if( Comp_Type != FILE_COMPRESSION_TYPE_NONE )
+    {
+        /* Check if we've found one already.  Indicate cascading if we did. */
+        if( SessionPtr->Decomp_Type != FILE_COMPRESSION_TYPE_NONE )
+        {
+            File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_CASC_COMP );
+            SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+        }
+        else
+        {
+            /* Found our first matching, supported filter type */
+            SessionPtr->Decomp_Type = Comp_Type;
+            SessionPtr->Decomp_State.PDF.Decomp_Type = Comp_Type;
+        }
+    }
+    else
+    {
+        File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_UNSUP_COMP_TYPE );
+        SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+    }
+}
+
+/* Parse the buffered Filter_Spec and create a stream decompression
+   mode and/or event alerts.  Return File_Decomp_OK if successfui.
+   Return File_Decomp_Error for a parsing error. */
+static fd_status_t Process_Filter_Spec( fd_session_p_t SessionPtr )
+{
+    /* The following string contains CHR_ARRAY_OPEN, CHR_ARRAY_CLOSE,
+       and CHR_NAME_SEP. */
+    const uint8_t Delim_Str[] = { "\011\012\014\015\040/[]" };
+    bool Found_Array = false;
+    bool Found_Token = false;
+    uint8_t *Filter;
+    uint8_t Length;
+    uint8_t c;
+    int Index;
+
+    fd_status_t Ret_Code = File_Decomp_OK;
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+
+    /* Assume the 'no compression' result */
+    SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+    Filter = NULL;
+    Length = 0;
+
+    for( Index=0; Index<p->Filter_Spec_Index; Index++ )
+    {
+        c = p->Filter_Spec_Buf[Index];
+
+        if( (c == 0) || (strchr( (char *)Delim_Str, (int)c ) != 0) )
+        {
+            if( c == CHR_ARRAY_OPEN )
+            {
+                /* Looks like an array starting, but we are already
+                   in an array, or have seen a filter spec already.  */
+                if( Found_Array || Found_Token || (Filter != NULL) )
+                {
+                    Ret_Code = File_Decomp_Error;
+                    break;
+                }
+                else
+                {
+                    Found_Array = true;
+                    Filter = NULL;
+                    Length = 0;
+                    continue;  // Nothing else to do, goto next char
+                }
+            }
+            else if( c == CHR_ARRAY_CLOSE )
+            {
+                /* We MUST have an array open at this point. */
+                if( !Found_Array )
+                {
+                    Ret_Code = File_Decomp_Error;
+                    break;
+                }
+                Found_Array = false;
+            }
+
+            /* The white-space or other separator terminates the
+               current filter name we are parsing. */
+            if( (Filter != NULL) && (Length > 0) )
+            {
+                Process_One_Filter( SessionPtr, Filter, Length );
+                Filter = NULL;
+                Length = 0;
+            }
+        }
+        else  // non-separator character
+        {
+            /* Start a token if we haven't already. */
+            if( Filter == NULL )
+            {
+                Found_Token = true;  // Used in the array syntax checking
+                Filter = &(p->Filter_Spec_Buf[Index]);
+                Length = 1;  // We've found one character so far
+            }
+            else
+            {
+                Length += 1;
+            }
+        }
+    }
+
+    /* Indicate an error is we exit the parsing with the array open */
+    if( Found_Array )
+        Ret_Code = File_Decomp_Error;
+
+    /* Any error code implies no compression type */
+    if( Ret_Code == File_Decomp_Error )
+        SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+    /* Look for case where the filter name ends at the
+       last character of the filter_spec. */
+    else if( (Filter != NULL) && (Length > 0) )
+        Process_One_Filter( SessionPtr, Filter, Length );
+
+    return( Ret_Code );
+}
+
+
+static inline void Init_Parser( fd_session_p_t SessionPtr )
+{
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+    /* The parser starts in the P_COMMENT state we start
+       parsing the file just after the signature is located
+       and the signature is syntactially a comment. */
+    p->State = P_COMMENT;
+    p->Parse_Stack_Index = 0; // Stack is empty
+}
+
+static inline fd_status_t Push_State( fd_PDF_Parse_p_t p )
+{
+    fd_PDF_Parse_Stack_p_t StckPtr;
+
+    if( p->Parse_Stack_Index >= (PARSE_STACK_LEN-1) )
+        return( File_Decomp_Error );
+
+    StckPtr = &(p->Parse_Stack[(p->Parse_Stack_Index)++]);
+
+    StckPtr->State = p->State;
+    StckPtr->Sub_State = p->Sub_State;
+
+    return( File_Decomp_OK );
+}
+
+static inline fd_status_t Pop_State( fd_PDF_Parse_p_t p )
+{
+    fd_PDF_Parse_Stack_p_t StckPtr;
+
+    if( p->Parse_Stack_Index == 0 )
+        return( File_Decomp_Error );
+
+    StckPtr = &(p->Parse_Stack[--(p->Parse_Stack_Index)]);
+
+    p->Elem_Index = 0;  // Reset to beginning of token as can't push/pop in mid-token
+    p->State = StckPtr->State;
+    p->Sub_State = StckPtr->Sub_State;
+
+    return( File_Decomp_OK );
+}
+
+/* If there's a previous state on the stack, return a pointer to it, else return NULL */
+static inline fd_PDF_Parse_Stack_p_t Get_Previous_State( fd_PDF_Parse_p_t p )
+{
+    if( p->Parse_Stack_Index == 0 )
+        return( (fd_PDF_Parse_Stack_p_t)NULL );
+
+    return( &(p->Parse_Stack[(p->Parse_Stack_Index)-1]) );
+}
+
+/* Objects are the heart and soul of the PDF.  In particular, we need to concentrate on Dictionary
+   objects and objects that map to the Filter element in Dictionaries.  'null' is a valid object'.
+   Objects can be recursively composed of arrays of objects. In our limited parsing paradigm, we
+   will only process the contents of top level Dictionaries and ignore deeper levels.  We will 
+   only explore Dictionary objects within Indirect Objects.  */
+static inline fd_status_t Handle_State_DICT_OBJECT( fd_session_p_t SessionPtr, uint8_t c )
+{
+    char Filter_Tok[] = TOK_DICT_FILT;
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+
+    /* enter with c being an EOL from the ind obj state */
+    if( p->State != P_DICT_OBJECT )
+    {
+        p->Sub_State = P_DICT_OPEN;  // Looking to open a Dict`
+        p->Dict_Nesting_Cnt = 0;  // No Dicts are 'active'
+        p->State = P_DICT_OBJECT;
+        p->Filter_Spec_Index = 0;
+        SessionPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+        return( File_Decomp_OK );
+    }
+
+    switch( p->Sub_State )
+    {
+        /* look for the first angle bracket */
+        case( P_DICT_OPEN ):
+        {
+            if( c == CHR_ANGLE_OPEN )
+            {
+                p->Sub_State = P_DICT_OPEN_TOK;
+            }
+            else if( !IS_WHITESPACE(c) )
+            {
+                /* for other objects, just skip and wait for the close of the
+                   indirect object as we don't parse objects other than Dict's. */
+                if( Pop_State( p ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+            }
+            break;
+        }
+        /* now look for the second angle bracket */
+        case( P_DICT_OPEN_TOK ):
+        {
+            if( c == CHR_ANGLE_OPEN )
+            {
+                /* Only ACTIVE if this is the opening of the
+                   'base level' Dict, NOT a nested one. */
+                if( p->Dict_Nesting_Cnt++ == 0 )
+                {
+                    p->Sub_State = P_DICT_ACTIVE;
+                }
+                else
+                {
+                    p->Sub_State = P_DICT_SKIP;
+                }
+            }
+            else
+            {
+                /* for other objects, just skip and wait for the close of the
+                   indirect object as we don't parse objects other than Dict's. */
+                if( Pop_State( p ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+            }
+            break;
+        }
+        case( P_DICT_SKIP ):
+        case( P_DICT_ACTIVE ):
+        {
+            /* Main purpose is to search for the value portion of the
+               /Filter entry.  Main loop looks for the /Filter token
+               and handles other diversion such as nested Dict objects.
+               If the /Filter token doesn't exist then we don't fill the
+               Filter_Spec_Buf[].  If in skip mode, no need to look for token. */
+            if( (p->Sub_State == P_DICT_ACTIVE) && c == Filter_Tok[p->Elem_Index++] )
+            {
+                if( Filter_Tok[p->Elem_Index] == '\0' )
+                {
+                    p->Sub_State = P_DICT_FILTER;
+                }
+            }
+            else
+            {
+                /* On a mis-match, reset back to the start of the token */
+                p->Elem_Index = 0;
+
+                /* we might find a Sub-Dict while we're looking */
+                if( c == CHR_ANGLE_OPEN )
+                {
+                    /* Save where we are, and process the Dict */
+                    if( Push_State( p ) != File_Decomp_OK )
+                        return( File_Decomp_Error );
+                    p->Sub_State = P_DICT_OPEN_TOK;
+                }
+                else if( c == CHR_ANGLE_CLOSE )
+                {
+                    if( Push_State( p ) != File_Decomp_OK )
+                        return( File_Decomp_Error );
+                    p->Sub_State = P_DICT_CLOSE_TOK;
+                }
+            }
+            break;
+        }
+
+        case( P_DICT_FILTER ):
+        {
+            if( (c == CHR_ANGLE_CLOSE) ||
+                ((c == CHR_NAME_SEP) && (p->Dict_Nesting_Cnt==3) ))  //  See the large comment below
+            {
+                if( c == CHR_ANGLE_CLOSE )
+                {
+                    if( Push_State( p ) != File_Decomp_OK )
+                        return( File_Decomp_Error );
+                    p->Sub_State = P_DICT_CLOSE_TOK;
+                }
+                else
+                {
+                    p->Sub_State = P_DICT_SKIP;
+                }
+                if( (Process_Filter_Spec( SessionPtr )  == File_Decomp_Error) )
+                    return( File_Decomp_Error );
+            }
+            else
+            {
+                /* Since we don't have a full object parse, we need to assure
+                   that we capture the entire filter spec string.  The '>' is always
+                   a terminator, but we also want to terminate on the next /Name entry
+                   after a possible array of /Names.  The Dict_Nesting_Cnt is used to 
+                   step through the transition options.  The '/' character is only a valid
+                   filter spec terminator if we've seen a valid array or one /Name entry. */
+                if( (c == CHR_NAME_SEP) && (p->Dict_Nesting_Cnt==1) )
+                    p->Dict_Nesting_Cnt = 3;
+                else if( (c == CHR_ARRAY_OPEN) && (p->Dict_Nesting_Cnt==1) )
+                    p->Dict_Nesting_Cnt = 2;
+                else if( (c == CHR_ARRAY_CLOSE) && (p->Dict_Nesting_Cnt==2) )
+                    p->Dict_Nesting_Cnt = 3;
+
+                if( p->Filter_Spec_Index < (FILTER_SPEC_BUF_LEN-1) )
+                {
+                    p->Filter_Spec_Buf[p->Filter_Spec_Index++] = c;
+                }
+                else
+                    return( File_Decomp_Error );
+            }
+            break;
+        }
+
+        case( P_DICT_CLOSE_TOK ):
+        {
+            if( c == CHR_ANGLE_CLOSE )
+            {
+                /*  Pop the temp state just prior to the first > */
+                if( Pop_State( p ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+
+                /* Pop back to the state before the <<.  */
+                /* But not so fast...  Look at what state/sub-state we are popping
+                   back to.  If it's IND_OBJ, AND we have an active filter type,
+                   we don't want to scan to the end of the stream but rather the beginning
+                   of the stream.  */
+                if( SessionPtr->Decomp_Type != FILE_COMPRESSION_TYPE_NONE )
+                {
+                    fd_PDF_Parse_Stack_p_t StckPtr;
+
+                    if( (StckPtr = Get_Previous_State( p )) == NULL )
+                    {
+                        /* There MUST be a previous state that got us here. */
+                        return( File_Decomp_Error );
+                    }
+                    else
+                    {
+                        if( (StckPtr->State == P_IND_OBJ) &&
+                            (StckPtr->Sub_State == P_ENDOBJ_TOKEN) )
+                        {
+                            StckPtr->Sub_State = P_STREAM_TOKEN;
+                        }
+                    }
+                }
+                if( Pop_State( p ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+            }
+            else
+                /* Return to where we looking (didn't get >>) */
+                if( Pop_State( p ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+            break;
+        }
+                
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+static inline fd_status_t Process_Stream( fd_PDF_Parse_p_t p )
+{
+    p->Sub_State = P_ENDSTREAM_TOKEN;
+    p->State = P_IND_OBJ;
+
+    if( Push_State( p ) == File_Decomp_Error )
+        return( File_Decomp_Error );
+    else
+        {
+            p->State = P_STREAM;
+            p->Sub_State = 0;
+        }
+    return( File_Decomp_OK );
+}
+
+/* Indirect Objects occur only at the top level of the file and comprise the
+   bulk of the file content. */
+static inline fd_status_t Handle_State_IND_OBJ( fd_session_p_t SessionPtr, uint8_t c )
+{
+    static uint8_t Ind_Obj_Token[] = { TOK_OBJ_OPEN };
+    static uint8_t Ind_Obj_End_Token[] = { TOK_OBJ_CLOSE };
+    static uint8_t Stream_Token[] = { TOK_STRM_OPEN };
+    static uint8_t Stream_End_Token[] = { TOK_STRM_CLOSE };
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+
+    /* Upon initial entry, setup state context */
+    if( p->State != P_IND_OBJ )
+    {
+        p->State = P_IND_OBJ;
+        p->Sub_State = P_OBJ_NUMBER;
+        p->Elem_Index = 1;
+        p->Elem_Buf[0] = c;
+        return( File_Decomp_OK );
+    }
+
+    switch( p->Sub_State )
+    {
+        case( P_OBJ_NUMBER ):
+        case( P_GEN_NUMBER ):
+        {
+            if( isdigit( c ) )
+            {
+                if( p->Elem_Index < (sizeof(p->Elem_Buf)-1))
+                {
+                    p->Elem_Buf[p->Elem_Index++] = c;
+                }
+                else 
+                    return( File_Decomp_Error );
+            }
+            else if( c == CHR_SPACE )
+            {
+                uint32_t Value;
+                p->Elem_Buf[p->Elem_Index] = '\0';
+                Value = (uint32_t)strtoul( (const char *)p->Elem_Buf, NULL, 10 );
+                if( p->Sub_State == P_OBJ_NUMBER )
+                {
+                    p->Obj_Number = Value;
+                    p->Sub_State = P_GEN_NUMBER;
+                    p->Elem_Index = 0;
+                }
+                else
+                {
+                    p->Gen_Number = Value;
+                    p->Sub_State = P_OBJ_TOKEN;
+                    p->Elem_Index = 0;
+                }
+            }
+            break;
+        }
+
+        case( P_OBJ_TOKEN ):
+        {
+            if( c == Ind_Obj_Token[p->Elem_Index++] )
+            {
+                if( Ind_Obj_Token[p->Elem_Index] == '\0' )
+                {
+                    p->Sub_State = P_OBJ_EOL;
+                    break;
+                }
+            }
+            else
+            {
+                return( File_Decomp_Error );
+            }
+        }
+
+        case( P_OBJ_EOL ):
+        {
+            if( IS_EOL(c) )
+            {
+                DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "Indirect Object: objnum: %u\n", p->Obj_Number););
+                p->Sub_State = P_ENDOBJ_TOKEN;
+                /* Save our place in the IND_OBJ and go process an OBJECT */
+                if( Push_State( p ) != File_Decomp_OK )
+                    return( File_Decomp_Error );
+                return( Handle_State_DICT_OBJECT( SessionPtr, c ) );
+            }
+
+            break;
+        }
+
+
+        case( P_STREAM_TOKEN ):
+        {
+            if( c == Stream_Token[p->Elem_Index++] )
+            {
+                if( Stream_Token[p->Elem_Index] == '\0' )
+                {
+                    /* Look for the limited EOL sequence */
+                    p->Sub_State = P_STREAM_EOL;
+                }
+                break;
+            }
+            else if( IS_WHITESPACE(c) )
+            {
+                p->Elem_Index = 0;  // reset and keep looking
+            }
+            else
+                return( File_Decomp_Error );
+            break;
+        }
+
+        case( P_STREAM_EOL ):
+        {
+            if( c == CHR_CR )
+            {
+                /* The next char MUST be a LF or error */
+                p->Sub_State = P_STREAM_LF;
+            }
+            else if( c == CHR_LF )
+            {
+                if( Process_Stream( p ) != File_Decomp_OK )
+                    return( File_Decomp_Error );
+            }
+            else
+                return( File_Decomp_Error );
+
+            break;
+        }
+
+        case( P_STREAM_LF ):
+        {
+            if( c == CHR_LF )
+            {
+                if( Process_Stream( p ) != File_Decomp_OK )
+                    return( File_Decomp_Error );
+            }
+            else
+                return( File_Decomp_Error );
+            break;
+        }
+
+        case( P_ENDSTREAM_TOKEN ):
+        {
+            if( c == Stream_End_Token[p->Elem_Index++] )
+            {
+                if( Stream_End_Token[p->Elem_Index] == '\0' )
+                {
+                    p->Sub_State = P_ENDOBJ_TOKEN;
+                }
+            }
+            else
+            {
+                p->Elem_Index = 0;  // reset and keep looking
+            }
+            break;
+        }
+
+        case( P_ENDOBJ_TOKEN ):
+        {
+            if( c == Ind_Obj_End_Token[p->Elem_Index++] )
+            {
+                if( Ind_Obj_End_Token[p->Elem_Index] == '\0' )
+                {
+                    /* we found the end of the indirect object, return
+                       back to the parent state (always START in this case) */
+                    return( Pop_State( p ) );
+                }
+            }
+            else
+            {
+                /* Since we don't necessarily handle all object types correctly,
+                   we will spin here searching for the end token.  Not the best, 
+                   but should work if we don't have a full object parser. */
+                p->Elem_Index = 0;  // reset and keep looking
+            }
+            break;
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+/* A simple state machine to process the xref/trailer/startxref file segments.  No
+   semantic processing and only rough syntactical processing to allow us to skip through
+   this segment. */
+static inline fd_status_t Handle_State_XREF( fd_session_p_t SessionPtr, uint8_t c )
+{
+    static uint8_t *Xref_Tok;
+    uint8_t Xref_End_Tok[] = { TOK_XRF_END };
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+
+    if( p->State != P_XREF )
+    {
+        p->Sub_State = P_XREF_TOKEN;
+        p->Elem_Index = 1;  // Aready matched the first char in START state
+        p->State = P_XREF;
+        Xref_Tok = (uint8_t *)((c == TOK_XRF_XREF[0]) ? TOK_XRF_XREF : TOK_XRF_STARTXREF);
+        return( File_Decomp_OK );
+    }
+
+    switch( p->Sub_State )
+    {
+        case( P_XREF_TOKEN ):
+        {
+            if( c == Xref_Tok[p->Elem_Index++] )
+            {
+                if( Xref_Tok[p->Elem_Index] == '\0' )
+                {
+                    p->Elem_Index = 0;
+                    p->Sub_State = P_XREF_END_TOKEN;
+                }
+            }
+            else
+            {
+                return( File_Decomp_Error );
+            }
+            break;
+        }
+
+        case( P_XREF_END_TOKEN ):
+        {
+            if( c == Xref_End_Tok[p->Elem_Index++] )
+            {
+                if( Xref_End_Tok[p->Elem_Index] == '\0' )
+                {
+                    p->State = P_START;
+                }
+            }
+            else
+            {
+                /* Since we don't necessarily handle all xref content correctly,
+                   we will spin here searching for the end token.  Not the best, 
+                   but should work if we don't have a full object parser. */
+                p->Elem_Index = 0;  // reset and keep looking
+            }
+
+            break;
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+static inline fd_status_t Handle_State_START( fd_session_p_t SessionPtr, uint8_t c )
+{
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+    /* Skip any whitespace.  This will include
+       the LF as part of a <CRLF> EOL token. */
+    if( IS_WHITESPACE(c) )
+    {
+        return( File_Decomp_OK );
+    }
+    if( c == CHR_COMMENT )
+    {
+        p->State = P_COMMENT;
+    }
+    else if( isdigit( c ) )
+    {
+        /* Save state and process an indirect object */
+        if( Push_State( p ) != File_Decomp_OK )
+            return( File_Decomp_Error );
+        return( Handle_State_IND_OBJ( SessionPtr, c ) );
+    }
+    else if( (c == TOK_XRF_XREF[0]) || (c == TOK_XRF_STARTXREF[0]) )
+    {
+        /* Save state and process the xref block */
+        if( Push_State( p ) != File_Decomp_OK )
+            return( File_Decomp_Error );
+         return( Handle_State_XREF( SessionPtr, c ) );
+    }
+    else if( !(IS_WHITESPACE(c)) )
+    {
+        /* If is not an ind_obj started, or a comment starting, then
+           we don't know what it is, so return an error. */
+        return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+/* Incrementally search the incoming data for a PDF compressed stream
+   (of the type that we can decompress).  Move bytes to outgoing data
+   up to the beginning of the compressed segment.  If the FILE_REVERT_BIT
+   is set in the Session, remove the /Filter spec that was located by
+   replacing the name with null.  */
+
+/* Parse file until input blocked or stream located. */
+static fd_status_t Locate_Stream_Beginning( fd_session_p_t SessionPtr )
+{
+    fd_PDF_Parse_p_t p = &(SessionPtr->Decomp_State.PDF.Parse);
+    fd_status_t Ret_Code = File_Decomp_OK;
+    uint8_t c;
+
+    while( 1 )
+    {
+        /* No reason to parse if there's no input or
+           room for output. */
+        if( SessionPtr->Avail_In == 0 )
+            return( File_Decomp_BlockIn );
+        if( SessionPtr->Avail_Out == 0 )
+            return( File_Decomp_BlockOut );
+
+        /* Get next byte in input queue */
+        c = *SessionPtr->Next_In;
+
+        switch( p->State )
+        {
+            /* The 'ground' state of the parser. All indirect objects
+               should be located at this level. */
+            case( P_START ):
+            {
+                if( (Ret_Code = Handle_State_START( SessionPtr, c )) != File_Decomp_OK )
+                    return( Ret_Code );
+                break;
+            }
+
+            case( P_COMMENT ):
+            {
+                /* CR or LF closes the comment.  The optional LF
+                   after a CR will be considered whitespace and
+                   removed in the P_START state. */
+                if( IS_EOL(c) )
+                    p->State = P_START;
+                break;
+            }
+
+            case( P_IND_OBJ ):
+            {
+                if( (Ret_Code = Handle_State_IND_OBJ( SessionPtr, c )) != File_Decomp_OK )
+                    return( Ret_Code );
+                break;
+            }
+
+            case( P_DICT_OBJECT ):
+            {
+                if( (Ret_Code = Handle_State_DICT_OBJECT( SessionPtr, c )) != File_Decomp_OK )
+                    return( Ret_Code );
+                break;
+            }
+            case( P_XREF ):
+            {
+                if( (Ret_Code = Handle_State_XREF( SessionPtr, c )) != File_Decomp_OK )
+                    return( Ret_Code );
+                break;
+            }
+
+            case( P_STREAM ):
+            {
+                return( File_Decomp_Complete );
+            }
+
+            default:
+                return( File_Decomp_Error );
+        }
+        /* After parsing, move the byte from the input to the
+           output stream.  We can only be here if there's input
+           available and output space. */
+        (void)Move_1(SessionPtr);
+    }
+}
+
+static fd_status_t Init_Stream( fd_session_p_t SessionPtr )
+{
+    fd_PDF_p_t StPtr = &(SessionPtr->Decomp_State.PDF);
+
+    switch( StPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_DEFLATE:
+        {
+            int z_ret;
+
+            z_stream *z_s = &(StPtr->PDF_Decomp_State.Deflate.StreamDeflate);
+
+            memset( (char *)z_s, 0, sizeof(z_stream));
+
+            z_s->zalloc = (alloc_func)NULL;
+            z_s->zfree = (free_func)NULL;
+            SYNC_IN(z_s)
+            z_ret = inflateInit2(z_s, 47);
+
+            if( z_ret != Z_OK )
+            {
+                File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_DEFL_FAILURE );
+                return( File_Decomp_Error );
+            }
+
+            break;
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+static fd_status_t Decomp_Stream( fd_session_p_t SessionPtr )
+{
+    fd_PDF_p_t StPtr = &(SessionPtr->Decomp_State.PDF);
+
+    /* No reason to decompress if there's no input or
+       room for output. */
+    if( SessionPtr->Avail_In == 0 )
+        return( File_Decomp_BlockIn );
+    if( SessionPtr->Avail_Out == 0 )
+        return( File_Decomp_BlockOut );
+
+    switch( StPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_DEFLATE:
+        {
+            int z_ret;
+            z_stream *z_s = &(StPtr->PDF_Decomp_State.Deflate.StreamDeflate);
+
+            SYNC_IN(z_s)
+            z_ret = inflate(z_s, Z_SYNC_FLUSH);
+
+            SYNC_OUT(z_s)
+
+            if( z_ret == Z_STREAM_END )
+            {
+                return( File_Decomp_Complete );
+            }
+
+            if( z_ret != Z_OK )
+            {
+                DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "Decompression Error: objnum: %u\n", StPtr->Parse.Obj_Number););
+                File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_DEFL_FAILURE );
+                return( File_Decomp_Error );
+            }
+
+            break;
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+/* After processing a stream, close the decompession engine
+   and return the state of the parser. */
+static fd_status_t Close_Stream( fd_session_p_t SessionPtr )
+{
+    /* Put the parser state back where it was interrupted */
+    if( Pop_State( &(SessionPtr->Decomp_State.PDF.Parse) ) == File_Decomp_Error )
+        return( File_Decomp_Error );
+
+    SessionPtr->Decomp_State.PDF.State = PDF_STATE_LOCATE_STREAM;
+    return( File_Decomp_OK );
+}
+
+/* Abort the decompression session upon command from caller. */
+fd_status_t File_Decomp_End_PDF( fd_session_p_t SessionPtr )
+{
+    fd_PDF_p_t StPtr;
+
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    StPtr = &(SessionPtr->Decomp_State.PDF);
+
+    if( (StPtr->State != PDF_STATE_INIT_STREAM) &&
+        (StPtr->State != PDF_STATE_PROCESS_STREAM) )
+        return( File_Decomp_OK );
+
+    switch( StPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_DEFLATE:
+        {
+            int z_ret;
+            z_stream *z_s = &(StPtr->PDF_Decomp_State.Deflate.StreamDeflate);
+
+            z_ret = inflateEnd(z_s);
+
+            if( z_ret != Z_OK )
+            {
+                File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_DEFL_FAILURE );
+                return( File_Decomp_Error );
+            }
+
+            break;
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+
+/* From caller, initialize PDF state machine. */
+fd_status_t File_Decomp_Init_PDF( fd_session_p_t SessionPtr )
+{
+    fd_PDF_p_t StPtr;
+
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    StPtr = &(SessionPtr->Decomp_State.PDF);
+
+    Init_Parser( SessionPtr );
+
+    StPtr->Decomp_Type = FILE_COMPRESSION_TYPE_NONE;
+
+    /* Search for Dictionary/Stream object. */
+    StPtr->State = PDF_STATE_LOCATE_STREAM;
+
+    return( File_Decomp_OK );
+}
+
+/* Run the PDF state machine */
+fd_status_t File_Decomp_PDF( fd_session_p_t SessionPtr )
+{
+    fd_status_t Ret_Code;
+
+    if( (SessionPtr == NULL) || (SessionPtr->File_Type != FILE_TYPE_PDF) )
+        return( File_Decomp_Error );
+
+    /* Process all data until blocked */
+    while( 1 )
+    {
+        switch( SessionPtr->Decomp_State.PDF.State )
+        {
+            case( PDF_STATE_LOCATE_STREAM ):
+            {
+                /* Will return File_Decomp_Complete if/when the start of a valid compressed
+                   stream is located.  Decomp_Type will be set. The parsing will be suspended.  */
+                if( (Ret_Code = Locate_Stream_Beginning( SessionPtr ) ) == File_Decomp_Error)
+                {
+                    SessionPtr->Error_Event = HI_SERVER_PDF_PARSE_FAILURE;
+                    return( File_Decomp_DecompError );
+                }
+
+                /* If we didn't succeed then get more input */
+                if( Ret_Code != File_Decomp_Complete )
+                    return( Ret_Code );
+
+                /* The Parsing state remains, we break out to perform the stream
+                   decompression. */
+                if( SessionPtr->Decomp_Type == FILE_COMPRESSION_TYPE_NONE )
+                {
+                    break;
+                }
+                else
+                {
+                    DEBUG_WRAP(DebugMessage(DEBUG_HTTPINSPECT, "Compressed stream of type: %u\n", SessionPtr->Decomp_Type););
+                    SessionPtr->Decomp_State.PDF.State = PDF_STATE_INIT_STREAM;
+                    /* If we've located the beginning of stream, set new state
+                       and fall into next state */
+                }
+            }
+
+            case( PDF_STATE_INIT_STREAM ):
+            {
+                /* Initialize the selected decompression engine. */
+                Ret_Code = Init_Stream( SessionPtr );
+                if( Ret_Code != File_Decomp_OK )
+                {
+                    Ret_Code = File_Decomp_End_PDF( SessionPtr );
+                    if( Close_Stream( SessionPtr ) != File_Decomp_OK )
+                        return( File_Decomp_Error );
+                    File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_DEFL_FAILURE );
+                    break;
+                }
+
+                SessionPtr->Decomp_State.PDF.State = PDF_STATE_PROCESS_STREAM;
+                /* INTENTIONAL FALL-THROUGH INTO PDF_STATE_PROCESS_STREAM CASE. */
+            }
+            case( PDF_STATE_PROCESS_STREAM ):
+            {
+                Ret_Code = Decomp_Stream( SessionPtr );
+                /* Has the decompressor indicated the end of the data */
+                if( Ret_Code == File_Decomp_Error )
+                {
+                    Ret_Code = File_Decomp_End_PDF( SessionPtr );
+                    if( Close_Stream( SessionPtr ) != File_Decomp_OK )
+                        return( File_Decomp_Error );
+                    File_Decomp_Alert( SessionPtr, HI_SERVER_PDF_DEFL_FAILURE );
+                    break;
+                }
+                /* OK -> circle back for more input */
+                else if( Ret_Code == File_Decomp_OK )
+                    break;
+                else if( Ret_Code != File_Decomp_Complete )
+                    return( Ret_Code );
+
+                /* Close the decompression engine */
+                if( (Ret_Code = File_Decomp_End_PDF( SessionPtr ) ) == File_Decomp_Error)
+                    return( File_Decomp_Error);
+
+                /* Put the parser state back where it was interrupted */
+                if( (Close_Stream( SessionPtr) ) == File_Decomp_Error )
+                    return( File_Decomp_Error );
+
+                break;
+            }
+
+            default:
+                return( File_Decomp_Error );
+        } // switch()
+    } // while()
+
+    return( File_Decomp_OK );
+}
+
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp_pdf.h b/src/service_inspectors/http_inspect/hi_file_decomp_pdf.h
new file mode 100644 (file)
index 0000000..8d71569
--- /dev/null
@@ -0,0 +1,82 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifndef HI_FILE_DECOMP_PDF_H
+#define HI_FILE_DECOMP_PDF_H
+
+#include <zlib.h>
+
+#define ELEM_BUF_LEN        (12)
+#define FILTER_SPEC_BUF_LEN (40)
+#define PARSE_STACK_LEN     (12)
+
+typedef enum pdf_states
+{
+    PDF_STATE_NEW,
+    PDF_STATE_LOCATE_STREAM,     /* Found sig bytes, looking for dictionary & stream*/
+    PDF_STATE_INIT_STREAM,       /* Init stream */
+    PDF_STATE_PROCESS_STREAM     /* Processing stream */
+} fd_PDF_States;
+
+typedef struct fd_PDF_Parse_Stack_s
+{
+    uint8_t State;
+    uint8_t Sub_State;
+} fd_PDF_Parse_Stack_t, *fd_PDF_Parse_Stack_p_t;
+
+typedef struct fd_PDF_Parse_s
+{
+    uint8_t Dict_Nesting_Cnt;
+    uint8_t Elem_Buf[ELEM_BUF_LEN];
+    uint8_t Elem_Index;
+    uint8_t Filter_Spec_Buf[FILTER_SPEC_BUF_LEN+1];
+    uint8_t Filter_Spec_Index;
+    fd_PDF_Parse_Stack_t Parse_Stack[PARSE_STACK_LEN];
+    uint8_t Parse_Stack_Index;
+    uint32_t Obj_Number;
+    uint32_t Gen_Number;
+    uint8_t Sub_State;
+    uint8_t State;
+} fd_PDF_Parse_t, *fd_PDF_Parse_p_t;
+
+typedef struct fd_PDF_Deflate_s
+{
+    z_stream StreamDeflate;
+} fd_PDF_Deflate_t;
+
+typedef struct fd_PDF_s
+{
+    union
+    {
+        fd_PDF_Deflate_t Deflate;
+    } PDF_Decomp_State;
+    fd_PDF_Parse_t Parse;
+    uint8_t Decomp_Type;
+    uint8_t State;
+} fd_PDF_t, *fd_PDF_p_t;
+
+/* API Functions */
+
+fd_status_t File_Decomp_Init_PDF( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_End_PDF( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_PDF(fd_session_p_t SessionPtr);
+
+#endif
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp_swf.cc b/src/service_inspectors/http_inspect/hi_file_decomp_swf.cc
new file mode 100644 (file)
index 0000000..43d8ddf
--- /dev/null
@@ -0,0 +1,340 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <zlib.h>
+#include <string.h>
+
+#ifdef LZMA
+#include <lzma.h>
+#endif
+
+#include "hi_file_decomp.h"
+#include "hi_file_decomp_swf.h"
+#include "hi_events.h"
+
+#ifdef LZMA
+#define LZMA_HEADER_LEN  (13)
+#define LZMA_PRP_OFFSET  (0)
+#define SWF_PRP_OFFSET   (9)
+#define LZMA_UCL_OFFSET  (5)
+#define SWF_UCL_OFFSET   (1)
+#define SWF_HDR_LEN      (SWF_SIG_LEN + SWF_VER_LEN + SWF_UCL_LEN)
+
+static fd_status_t File_Decomp_Process_LZMA_Header( fd_session_p_t SessionPtr )
+{
+    uint8_t LZMA_Header[LZMA_HEADER_LEN];
+    uint8_t *SWF_Header = SessionPtr->Decomp_State.SWF.Header_Bytes;
+    uint64_t LZMA_Uncomp_Len;
+    uint32_t SWF_Uncomp_Len;
+    int idx;
+
+    lzma_ret l_ret;
+    lzma_stream *l_s = &(SessionPtr->Decomp_State.SWF.StreamLZMA);
+
+    SWF_Uncomp_Len = 0;
+    /* Read little-endian into value */
+    for( idx=0; idx<4; idx++ )
+        SWF_Uncomp_Len +=
+            (uint32_t)((uint8_t)(*(SWF_Header + SWF_UCL_OFFSET + idx)) << (8*idx) );
+
+    if( SWF_Uncomp_Len < SWF_HDR_LEN )
+    {
+        SessionPtr->Error_Event = HI_SERVER_SWF_LZMA_FAILURE;
+        return( File_Decomp_DecompError );
+    }
+    
+    LZMA_Uncomp_Len = (uint64_t)(SWF_Uncomp_Len - (SWF_HDR_LEN));
+
+    /* Write little-endian from value */
+    for( idx=0; idx<8; idx++ )
+        *(LZMA_Header + LZMA_UCL_OFFSET + idx) =
+            (uint8_t)(LZMA_Uncomp_Len & (0xff << idx));
+
+    LZMA_Uncomp_Len = (uint64_t)(SWF_Uncomp_Len - (SWF_HDR_LEN));
+
+    /* Move the LZMA Properties */
+    for( idx=0; idx<SWF_LZMA_PRP_LEN; idx++ )
+        LZMA_Header[LZMA_PRP_OFFSET + idx] = *(SWF_Header + SWF_PRP_OFFSET + idx);
+
+    l_s->next_out = SessionPtr->Next_Out;
+    l_s->avail_out = SessionPtr->Avail_Out;
+    l_s->total_out = SessionPtr->Total_Out;
+
+    l_s->next_in = LZMA_Header;
+    l_s->avail_in = sizeof(LZMA_Header);
+
+    l_ret = lzma_code(l_s, LZMA_RUN);
+
+    SessionPtr->Next_Out = l_s->next_out;
+    SessionPtr->Avail_Out = l_s->avail_out;
+    SessionPtr->Total_Out = l_s->total_out;
+
+    if( l_ret != LZMA_OK )
+    {
+        SessionPtr->Error_Event = HI_SERVER_SWF_LZMA_FAILURE;
+        return( File_Decomp_DecompError );
+    }
+
+    return( File_Decomp_OK );
+}
+#endif
+
+static fd_status_t Decomp( fd_session_p_t SessionPtr )
+{
+    switch( SessionPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_ZLIB:
+        {
+            int z_ret;
+            z_stream *z_s = &(SessionPtr->Decomp_State.SWF.StreamZLIB);
+
+            SYNC_IN(z_s)
+            z_ret = inflate(z_s, Z_SYNC_FLUSH);
+
+            SYNC_OUT(z_s)
+
+            if( z_ret == Z_STREAM_END )
+            {
+                return( File_Decomp_Complete );
+            }
+
+            if( z_ret != Z_OK )
+            {
+                SessionPtr->Error_Event = HI_SERVER_SWF_ZLIB_FAILURE;
+                return( File_Decomp_DecompError );
+            }
+
+
+            break;
+        }
+#ifdef LZMA
+        case FILE_COMPRESSION_TYPE_LZMA:
+        {
+            lzma_ret l_ret;
+            lzma_stream *l_s = &(SessionPtr->Decomp_State.SWF.StreamLZMA);
+
+            SYNC_IN(l_s)
+            l_ret = lzma_code(l_s, LZMA_RUN);
+
+            SYNC_OUT(l_s)
+
+            if( l_ret == LZMA_STREAM_END )
+            {
+                return( File_Decomp_Complete );
+            }
+
+            if( l_ret != LZMA_OK )
+            {
+                SessionPtr->Error_Event = HI_SERVER_SWF_LZMA_FAILURE;
+                return( File_Decomp_DecompError );
+            }
+
+            break;
+        }
+#endif
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+fd_status_t File_Decomp_End_SWF( fd_session_p_t SessionPtr )
+{
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    switch( SessionPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_ZLIB:
+        {
+            int z_ret;
+            z_stream *z_s = &(SessionPtr->Decomp_State.SWF.StreamZLIB);
+
+            z_ret = inflateEnd(z_s);
+
+            if( z_ret != Z_OK )
+            {
+                SessionPtr->Error_Event = HI_SERVER_SWF_ZLIB_FAILURE;
+                return( File_Decomp_DecompError );
+            }
+
+            break;
+        }
+#ifdef LZMA
+        case FILE_COMPRESSION_TYPE_LZMA:
+        {
+            lzma_stream *l_s = &(SessionPtr->Decomp_State.SWF.StreamLZMA);
+
+            lzma_end(l_s);
+
+            break;
+        }
+#endif
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+
+fd_status_t File_Decomp_Init_SWF( fd_session_p_t SessionPtr )
+{
+    if( SessionPtr == NULL )
+        return( File_Decomp_Error );
+
+    /* Indicate the we need to look for the remainder of the
+       uncompressed header. */
+    SessionPtr->Decomp_State.SWF.State = SWF_STATE_GET_HEADER;
+    SessionPtr->Decomp_State.SWF.Header_Cnt = 0;
+
+    switch( SessionPtr->Decomp_Type )
+    {
+        case FILE_COMPRESSION_TYPE_ZLIB:
+        {
+            int z_ret;
+            z_stream *z_s;
+
+            SessionPtr->Decomp_State.SWF.Header_Len = 
+                SWF_VER_LEN + SWF_UCL_LEN;
+
+            z_s = &(SessionPtr->Decomp_State.SWF.StreamZLIB);
+
+            memset( (char *)z_s, 0, sizeof(z_stream));
+
+            z_s->zalloc = (alloc_func)NULL;
+            z_s->zfree = (free_func)NULL;
+            SYNC_IN(z_s)
+            z_ret = inflateInit(z_s);
+
+            if( z_ret != Z_OK )
+            {
+                SessionPtr->Error_Event = HI_SERVER_SWF_ZLIB_FAILURE;
+                return( File_Decomp_DecompError );
+            }
+
+            break;
+        }
+#ifdef LZMA
+        case FILE_COMPRESSION_TYPE_LZMA:
+        {
+            lzma_ret l_ret;
+            lzma_stream *l_s;
+
+            SessionPtr->Decomp_State.SWF.Header_Len = 
+                SWF_VER_LEN + SWF_UCL_LEN + SWF_LZMA_CML_LEN + SWF_LZMA_PRP_LEN;
+
+            l_s = &(SessionPtr->Decomp_State.SWF.StreamLZMA);
+
+            memset( (char *)l_s, 0, sizeof(lzma_stream));
+
+            SYNC_IN(l_s)
+            l_ret = lzma_alone_decoder(l_s, UINT64_MAX);
+
+            if( l_ret != LZMA_OK )
+            {
+                SessionPtr->Error_Event = HI_SERVER_SWF_LZMA_FAILURE;
+                return( File_Decomp_DecompError );
+            }
+
+
+            break;
+        }
+#endif
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
+fd_status_t File_Decomp_SWF( fd_session_p_t SessionPtr )
+{
+    fd_status_t Ret_Code;
+
+    if( (SessionPtr == NULL) || (SessionPtr->File_Type != FILE_TYPE_SWF) )
+        return( File_Decomp_Error );
+
+    /* Are we still looking for the balance of the uncompressed header? */
+    switch( SessionPtr->Decomp_State.SWF.State )
+    {
+        case( SWF_STATE_GET_HEADER ):
+        {
+            uint8_t *Cnt_Ptr = &(SessionPtr->Decomp_State.SWF.Header_Cnt);  // For convenience
+            uint8_t *Len_Ptr = &(SessionPtr->Decomp_State.SWF.Header_Len);  // For convenience
+
+            while( *Len_Ptr > *Cnt_Ptr )
+            {
+                if( SessionPtr->Avail_In == 0 )
+                    return( File_Decomp_BlockIn );
+
+                if( SessionPtr->Avail_Out == 0 )
+                    return( File_Decomp_BlockOut );
+
+                SessionPtr->Decomp_State.SWF.Header_Bytes[*Cnt_Ptr] =
+                    *(SessionPtr->Next_In);
+
+                (void)Move_1(SessionPtr);
+                *Cnt_Ptr += 1;
+            }
+
+            SessionPtr->Decomp_State.SWF.State = SWF_STATE_PROC_HEADER;
+            /* INTENTIONAL FALL-THROUGH INTO SWF_STATE_PROC_HEADER CASE. */
+        }
+        case( SWF_STATE_PROC_HEADER ):
+        {
+#ifdef LZMA
+            if( SessionPtr->Decomp_Type == FILE_COMPRESSION_TYPE_LZMA )
+            {
+                Ret_Code = File_Decomp_Process_LZMA_Header( SessionPtr );
+                if( Ret_Code != File_Decomp_OK )
+                    return( Ret_Code );
+            }
+#endif
+
+            SessionPtr->Decomp_State.SWF.State = SWF_STATE_DATA;
+            /* INTENTIONAL FALL-THROUGH INTO SWF_STATE_DATA CASE. */
+        }
+        case( SWF_STATE_DATA ):
+        {
+            Ret_Code = Decomp( SessionPtr );
+            if( Ret_Code != File_Decomp_Complete )
+                return( Ret_Code );
+
+            Ret_Code = File_Decomp_End_SWF( SessionPtr );
+            if( Ret_Code != File_Decomp_OK )
+                return( Ret_Code );
+
+            return( File_Decomp_Complete );
+        }
+        default:
+            return( File_Decomp_Error );
+    }
+
+    return( File_Decomp_OK );
+}
+
diff --git a/src/service_inspectors/http_inspect/hi_file_decomp_swf.h b/src/service_inspectors/http_inspect/hi_file_decomp_swf.h
new file mode 100644 (file)
index 0000000..46c2433
--- /dev/null
@@ -0,0 +1,76 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifndef HI_FILE_DECOMP_SWF_H
+#define HI_FILE_DECOMP_SWF_H
+
+#include <zlib.h>
+#ifdef LZMA
+#include <lzma.h>
+#endif
+
+/* Both ZLIB & LZMA files have an uncompressed eight byte header.  The signature is
+   three bytes.  The header consists of a three byte sig, a one byte version,
+   and a four byte uncompressed length (little-endian).  */
+
+#define SWF_SIG_LEN       (3)
+#define SWF_VER_LEN       (1)
+#define SWF_UCL_LEN       (4)
+
+/* LZMA Files have an additional nine bytes of header prior to the compressed data.
+   This includes a four byte compressed length (little-endian) and five bytes
+   of LZMA properties. */
+#define SWF_LZMA_CML_LEN  (4)
+#define SWF_LZMA_PRP_LEN  (5)
+
+/* AFTER the sig, the max number of header bytes to fetch.
+   VER+UCL+CML+LZMA_PRP -> 14 bytes. */
+#define SWF_MAX_HEADER    (14)
+
+/* Types */
+
+typedef enum swf_states
+{
+    SWF_STATE_NEW,
+    SWF_STATE_GET_HEADER,     /* Found sig bytes, looking for end of uncomp header */
+    SWF_STATE_PROC_HEADER,    /* Found header bytes, now process the header */
+    SWF_STATE_DATA            /* Done with header, looking for start of data */
+} fd_SWF_States;
+
+typedef struct fd_SWF_s
+{
+    z_stream StreamZLIB;
+#ifdef LZMA
+    lzma_stream StreamLZMA;
+#endif
+    uint8_t Header_Bytes[SWF_MAX_HEADER];
+    uint8_t State;
+    uint8_t Header_Len;
+    uint8_t Header_Cnt;
+} fd_SWF_t;
+
+/* API Functions */
+
+fd_status_t File_Decomp_Init_SWF( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_SWF( fd_session_p_t SessionPtr );
+
+fd_status_t File_Decomp_End_SWF( fd_session_p_t SessionPtr );
+
+#endif
index ab000148211f6cbe2c7dfe9c1a683e0a46ed1bd0..db444383dee85bc3010a41a296bd0251712c22d9 100644 (file)
@@ -132,17 +132,17 @@ HttpFlowData::HttpFlowData() : FlowData(flow_id)
 
 HttpFlowData::~HttpFlowData()
 {
-    FreeHttpsessionData(&session);
+    FreeHttpSessionData(&session);
 }
 
-HttpsessionData* SetNewHttpsessionData(Packet *p, void*)
+HttpSessionData* SetNewHttpSessionData(Packet *p, void*)
 {
     HttpFlowData* fd = new HttpFlowData;
     p->flow->set_application_data(fd);
     return &fd->session;
 }
 
-static HttpsessionData* get_session_data(Flow* flow)
+static HttpSessionData* get_session_data(Flow* flow)
 {
     HttpFlowData* fd = (HttpFlowData*)flow->get_application_data(
         HttpFlowData::flow_id);
@@ -159,6 +159,14 @@ void HttpInspectRegisterXtraDataFuncs()
     xtra_jsnorm_id = stream.reg_xtra_data_cb(GetHttpJSNormData);
 }
 
+static void PrintFileDecompOpt(HTTPINSPECT_CONF *ServerConf)
+{
+    LogMessage("      Decompress response files: %s %s %s\n",
+               ((ServerConf->file_decomp_modes & FILE_SWF_ZLIB_BIT) != 0) ? "SWF-ZLIB" : "",
+               ((ServerConf->file_decomp_modes & FILE_SWF_LZMA_BIT) != 0) ? "SWF-LZMA" : "",
+               ((ServerConf->file_decomp_modes & FILE_PDF_DEFL_BIT) != 0) ? "PDF-DEFL" : "");
+}
+
 static int PrintConfOpt(HTTPINSPECT_CONF_OPT *ConfOpt, const char *Option)
 {
     if(!ConfOpt || !Option)
@@ -239,6 +247,7 @@ int PrintServerConf(HTTPINSPECT_CONF *ServerConf)
                ServerConf->log_hostname ? "YES"  :  "NO");
     LogMessage("      Extract Gzip from responses: %s\n",
                ServerConf->extract_gzip ? "YES" : "NO");
+    PrintFileDecompOpt(ServerConf);
 
     PrintConfOpt(&ServerConf->ascii, "Ascii");
     PrintConfOpt(&ServerConf->double_decoding, "Double Decoding");
@@ -425,7 +434,7 @@ static inline FilePosition getFilePoistion(Packet *p)
 // eg just once when captured; this function is called on every packet and 
 // repeatedly sets the flags on session
 static inline void HttpLogFuncs(
-    HttpsessionData *hsd, Packet *p, int iCallDetect )
+    HttpSessionData *hsd, Packet *p, int iCallDetect )
 {
     if(!hsd)
         return;
@@ -502,7 +511,7 @@ int HttpInspectMain(HTTPINSPECT_CONF* conf, Packet *p)
     int iInspectMode = 0;
     int iRet;
     int iCallDetect = 1;
-    HttpsessionData *hsd = NULL;
+    HttpSessionData *hsd = NULL;
 
     PROFILE_VARS;
 
@@ -600,7 +609,7 @@ int HttpInspectMain(HTTPINSPECT_CONF* conf, Packet *p)
     }
 
     if (hsd == NULL)
-        hsd = SetNewHttpsessionData(p, (void *)session);
+        hsd = SetNewHttpSessionData(p, (void *)session);
     else
     {
         /* Gzip data should not be logged with all the packets of the session.*/
@@ -1000,7 +1009,50 @@ int HttpInspectMain(HTTPINSPECT_CONF* conf, Packet *p)
                      detect_data_size = 0;
                  }
 
-                 set_file_data((uint8_t *)session->server.response.body, detect_data_size);
+                 /* Do we have a file decompression object? */
+                 if( hsd->fd_state != 0 )
+                 {
+                     fd_status_t Ret_Code;
+
+                     uint16_t Data_Len;
+                     const uint8_t *Data;
+
+                     hsd->fd_state->Next_In = (uint8_t*)(Data = session->server.response.body);
+                     hsd->fd_state->Avail_In = (Data_Len = (uint16_t)detect_data_size);
+
+                     (void)File_Decomp_SetBuf( hsd->fd_state );
+
+                     Ret_Code = File_Decomp( hsd->fd_state );
+
+                     if( Ret_Code == File_Decomp_DecompError )
+                     {
+                         session->server.response.body = Data;
+                         session->server.response.body_size = Data_Len;
+
+                         hi_set_event(GID_HTTP_SERVER, hsd->fd_state->Error_Event);
+                         File_Decomp_StopFree( hsd->fd_state );
+                         hsd->fd_state = NULL;
+                      }
+                     /* If we didn't find a Sig, then clear the File_Decomp state
+                        and don't keep looking. */
+                     else if( Ret_Code == File_Decomp_NoSig )
+                     {
+                         File_Decomp_StopFree( hsd->fd_state );
+                         hsd->fd_state = NULL;
+                     }
+                     else
+                     {
+                         session->server.response.body = hsd->fd_state->Buffer;
+                         session->server.response.body_size = hsd->fd_state->Total_Out;
+                     }
+
+                     set_file_data((uint8_t *)session->server.response.body, (uint16_t)session->server.response.body_size);
+                 }
+
+                 else
+                 {
+                     set_file_data((uint8_t *)session->server.response.body, detect_data_size);
+                 }
 
                  if (PacketHasPAFPayload(p)
                      && file_api->file_process(p,(uint8_t *)session->server.response.body, (uint16_t)session->server.response.body_size,
@@ -1065,7 +1117,7 @@ int HttpInspectInitializeGlobalConfig(HTTPINSPECT_GLOBAL_CONF* config)
     if (iRet)
         return iRet;
 
-    iRet = hi_client_init(config);
+    iRet = hi_client_init();
     if (iRet)
         return iRet;
 
@@ -1075,9 +1127,9 @@ int HttpInspectInitializeGlobalConfig(HTTPINSPECT_GLOBAL_CONF* config)
     return 0;
 }
 
-void FreeHttpsessionData(void *data)
+void FreeHttpSessionData(void *data)
 {
-    HttpsessionData *hsd = (HttpsessionData *)data;
+    HttpSessionData *hsd = (HttpSessionData *)data;
 
     if (hsd->decomp_state != NULL)
     {
@@ -1092,11 +1144,17 @@ void FreeHttpsessionData(void *data)
         sfip_free(hsd->true_ip);
 
     file_api->free_mime_session(hsd->mime_ssn);
+
+    if( hsd->fd_state != 0 )
+    {
+        File_Decomp_StopFree(hsd->fd_state);   // Stop & Stop &  Free fd session object
+        hsd->fd_state = NULL;                  // ...just for good measure
+    }
 }
 
 int GetHttpTrueIP(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 {
-    HttpsessionData* hsd = get_session_data(flow);
+    HttpSessionData* hsd = get_session_data(flow);
 
     if(!hsd->true_ip)
         return 0;
@@ -1119,7 +1177,7 @@ int GetHttpTrueIP(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 
 int IsGzipData(Flow* flow)
 {
-    HttpsessionData *hsd = NULL;
+    HttpSessionData *hsd = NULL;
 
     if (flow == NULL)
         return -1;
@@ -1152,7 +1210,7 @@ int GetHttpGzipData(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 
 int IsJSNormData(Flow* flow)
 {
-    HttpsessionData *hsd = NULL;
+    HttpSessionData *hsd = NULL;
 
     if (flow == NULL)
         return -1;
@@ -1184,7 +1242,7 @@ int GetHttpJSNormData(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 
 int GetHttpUriData(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 {
-    HttpsessionData *hsd = NULL;
+    HttpSessionData *hsd = NULL;
         
     if (flow == NULL)
         return 0;
@@ -1208,7 +1266,7 @@ int GetHttpUriData(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 
 int GetHttpHostnameData(Flow* flow, uint8_t **buf, uint32_t *len, uint32_t *type)
 {
-    HttpsessionData *hsd = NULL;
+    HttpSessionData *hsd = NULL;
         
     if (flow == NULL)
         return 0;
index 73cec8fb8b94f39562c82af7530c6f6c8c002122..668cbe0d2c1b92fca60eee0d48508b4dd2229000 100644 (file)
@@ -102,9 +102,8 @@ typedef struct s_HTTP_LOG_STATE
     uint8_t hostname_extracted[MAX_HOSTNAME];
 }HTTP_LOG_STATE;
 
-typedef struct _HttpsessionData
+typedef struct _HttpSessionData
 {
-    uint32_t event_flags;
     HTTP_RESP_STATE resp_state;
     DECOMPRESS_STATE *decomp_state;
     HTTP_LOG_STATE *log_state;
@@ -114,7 +113,8 @@ typedef struct _HttpsessionData
     uint8_t cli_small_chunk_count;
     uint8_t srv_small_chunk_count;
     MimeState *mime_ssn;
-} HttpsessionData;
+    fd_session_p_t fd_state;
+} HttpSessionData;
 
 class HttpFlowData : public FlowData
 {
@@ -126,7 +126,7 @@ public:
 
 public:
     static unsigned flow_id;
-    HttpsessionData session;
+    HttpSessionData session;
 };
 
 typedef struct _HISearch
@@ -181,7 +181,7 @@ extern THREAD_LOCAL HISearch hi_html_search[HTML_LAST];
 extern THREAD_LOCAL HISearch *hi_current_search;
 extern THREAD_LOCAL HISearchInfo hi_search_info;
 
-void ApplyFlowDepth(HTTPINSPECT_CONF *, Packet *, HttpsessionData *, int, int, uint32_t);
+void ApplyFlowDepth(HTTPINSPECT_CONF *, Packet *, HttpSessionData *, int, int, uint32_t);
 void HttpInspectRegisterXtraDataFuncs();
 
 int HttpInspectMain(HTTPINSPECT_CONF *GlobalConf, Packet *p);
@@ -189,8 +189,8 @@ int ProcessGlobalConf(HTTPINSPECT_GLOBAL_CONF *, char *, int);
 int PrintGlobalConf(HTTPINSPECT_GLOBAL_CONF *);
 int PrintServerConf(HTTPINSPECT_CONF*);
 int HttpInspectInitializeGlobalConfig(HTTPINSPECT_GLOBAL_CONF*);
-HttpsessionData * SetNewHttpsessionData(Packet *, void *);
-void FreeHttpsessionData(void *data);
+HttpSessionData * SetNewHttpSessionData(Packet *, void *);
+void FreeHttpSessionData(void *data);
 int GetHttpTrueIP(Flow*, uint8_t **buf, uint32_t *len, uint32_t *type);
 int GetHttpGzipData(Flow*, uint8_t **buf, uint32_t *len, uint32_t *type);
 int GetHttpJSNormData(Flow*, uint8_t **buf, uint32_t *len, uint32_t *type);
@@ -230,7 +230,7 @@ static inline void ResetRespState(HTTP_RESP_STATE *ds)
     ds->max_seq = 0;
 }
 
-static inline int SetLogBuffers(HttpsessionData *hsd)
+static inline int SetLogBuffers(HttpSessionData *hsd)
 {
     int iRet = 0;
 
index 785652413ff930cddfc29c5268473aeed877d57e..52800e4ed61befc23a3daf8c4976838288f7eb15 100644 (file)
@@ -61,7 +61,7 @@
 */
 
 int hi_mi_mode_inspection(HI_SESSION *session, int iInspectMode,
-        Packet *p, HttpsessionData *hsd)
+        Packet *p, HttpSessionData *hsd)
 {
     int iRet;
     if (!session || !p->data || (p->dsize == 0))
index a475478f9e15fdc0f1b4e4628bfae4cc392d2ae7..a71f3550ecf5f586d5d826b7bb111741df6aba7b 100644 (file)
@@ -36,7 +36,7 @@
 #include "hi_include.h"
 #include "hi_main.h"
 
-int hi_mi_mode_inspection(HI_SESSION *session, int iInspectMode, Packet *p, HttpsessionData *);
+int hi_mi_mode_inspection(HI_SESSION *session, int iInspectMode, Packet *p, HttpSessionData *);
 
 #endif
 
index f6abbf4b79f6429023ca0e66e748870b0d43b9c2..15ea6678b280978cacb6d3df40ad469933cdea87 100644 (file)
@@ -350,12 +350,17 @@ static const Parameter hi_profile_server_params[] =
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
-
 static const Parameter hi_server_params[] =
 {
     { "allow_proxy_use", Parameter::PT_BOOL, nullptr, "false",
       "don't alert on proxy use for this server" },
 
+    { "decompress_pdf", Parameter::PT_BOOL, nullptr, "false",
+      "????" }, // FIXIT-M need to figure out this parameter format and implement it
+
+    { "decompress_swf", Parameter::PT_BOOL, nullptr, "false",
+      "????" }, // FIXIT-M need to figure out this parameter format and implement it with deflate and lzma
+
     { "enable_cookies", Parameter::PT_BOOL, nullptr, "true",
       "extract cookies" },
 
@@ -413,6 +418,9 @@ static const Parameter hi_server_params[] =
     { "unlimited_decompress", Parameter::PT_BOOL, nullptr, "true",
       "decompress across multiple packets" },
 
+    { "xff_headers", Parameter::PT_BOOL, nullptr, "false",
+      "????" }, // FIXIT-M need to figure out this parameter format and implement it
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -429,6 +437,12 @@ static const RuleMap hi_server_rules[] =
     { HI_SERVER_JS_OBFUSCATION_EXCD, HI_SERVER_JS_OBFUSCATION_EXCD_STR },
     { HI_SERVER_JS_EXCESS_WS, HI_SERVER_JS_EXCESS_WS_STR },
     { HI_SERVER_MIXED_ENCODINGS, HI_SERVER_MIXED_ENCODINGS_STR },
+    { HI_SERVER_SWF_ZLIB_FAILURE, HI_SERVER_SWF_ZLIB_FAILURE_STR },
+    { HI_SERVER_SWF_LZMA_FAILURE, HI_SERVER_SWF_LZMA_FAILURE_STR },
+    { HI_SERVER_PDF_DEFL_FAILURE, HI_SERVER_PDF_DEFL_FAILURE_STR },
+    { HI_SERVER_PDF_UNSUP_COMP_TYPE, HI_SERVER_PDF_UNSUP_COMP_TYPE_STR },
+    { HI_SERVER_PDF_CASC_COMP, HI_SERVER_PDF_CASC_COMP_STR },
+    { HI_SERVER_PDF_PARSE_FAILURE, HI_SERVER_PDF_PARSE_FAILURE_STR },
     { 0, nullptr }
 };
 
@@ -480,6 +494,12 @@ bool HttpServerModule::set(const char*, Value& v, SnortConfig*)
     else if ( v.is("code_page") )
         server->iis_unicode_codepage = v.get_long();
 
+    else if ( v.is("decompress_pdf") ); // FIXIT-M need to figure this out and implement it
+
+    else if ( v.is("decompress_swf") ); // FIXIT-M need to figure this out and implement it
+                                        // including #define DECOMPRESS_DEFLATE "deflate" and
+                                        // including #define DECOMPRESS_LZMA "lzma"
+
     else if ( v.is("directory") )
         server->directory.on = v.get_bool();
 
@@ -597,6 +617,8 @@ bool HttpServerModule::set(const char*, Value& v, SnortConfig*)
     else if ( v.is("whitespace_chars") )
         v.get_bits(server->whitespace);
 
+    else if ( v.is("xff_headers") ); // FIXIT-M need to figure this out and implement it
+
     else
         return false;
 
index ffd702ed6f30b303a2550658b7e806bb14f3795a..ba064de45a35e1fc44db9cea4c4b022be0262bd0 100644 (file)
@@ -87,8 +87,8 @@ typedef struct s_URI_NORM_STATE
 typedef int (*DECODE_FUNC)(HI_SESSION *, const u_char *,
                           const u_char *, const u_char **, URI_NORM_STATE *, uint16_t *);
 
+static THREAD_LOCAL bool byte_decoded=false;
 
-bool byte_decoded=false;
 /*
 **  NAME
 **    GetPtr::
@@ -1171,6 +1171,18 @@ static int CheckLongDir(HI_SESSION *session, URI_NORM_STATE *norm_state,
     return HI_SUCCESS;
 }
 
+/*
+**  NAME
+**    EndPathField::
+*/
+/* This function determines whether a character marks the end of the URI path field.
+** It recognizes the query field '?' and fragment field '#' delimiters.
+** It will not accept a percent-encoded character as a valid delimiter.
+*/
+static inline bool EndPathField (bool percent_encoded, u_char uri_character) {
+    return ((uri_character == '?') || (uri_character == '#')) && !percent_encoded;
+}
+
 /*
 **  NAME
 **    InspectUriChar::
@@ -1323,6 +1335,14 @@ static inline int InspectUriChar(HI_SESSION *session, int iChar,
                 }
             }
 
+            // This block is necessary to detect '?' and '#' delimiters that immediately follow a '/'.
+            if(EndPathField(byte_decoded, (u_char)iDir))
+            {
+                //  This is the end of the path field. Check for a long directory following.
+                CheckLongDir(session, norm_state, *ub_ptr);
+                norm_state->param = *ub_ptr;
+            }
+
             **ub_ptr = (u_char)iDir;
             (*ub_ptr)++;
         }
@@ -1330,14 +1350,9 @@ static inline int InspectUriChar(HI_SESSION *session, int iChar,
         return HI_SUCCESS;
     }
 
-    if((!byte_decoded && (u_char)iChar == '?'))
+    if(EndPathField(byte_decoded, (u_char)iChar))
     {
-        /*
-        **  We assume that this is the beginning of the parameter field,
-        **  and check for a long directory following.  Event though seeing
-        **  a question mark does not guarantee the parameter field, thanks
-        **  IIS.
-        */
+        // This is the end of the path field. Check for a long directory following.
         CheckLongDir(session, norm_state, *ub_ptr);
         norm_state->param = *ub_ptr;
     }
@@ -1485,7 +1500,7 @@ int hi_norm_uri(HI_SESSION *session, u_char *uribuf, int *uribuf_size,
 **  @retval HI_SUCCESS      function successful
 **  @retval HI_INVALID_ARG  invalid argument
 */
-int hi_normalization(HI_SESSION *session, int iInspectMode, HttpsessionData *hsd)
+int hi_normalization(HI_SESSION *session, int iInspectMode, HttpSessionData *hsd)
 {
     int iRet;
 
index a9a41768763ffb9b505349b68c39244d20f8bd3a..a12b81949b3a49d86f64135dff78a5a81ca68c4c 100644 (file)
@@ -40,7 +40,7 @@
 
 #define MAX_URI 8192
 
-int hi_normalization(HI_SESSION *session, int iInspectMode, HttpsessionData *hsd);
+int hi_normalization(HI_SESSION *session, int iInspectMode, HttpSessionData *hsd);
 int hi_norm_uri(HI_SESSION *session, u_char *uribuf,int *uribuf_size,
                 const u_char *uri, int uri_size, uint16_t *encodeType);
 
index f25a077aaa17c9ba518f35f7edce5a098285d2ee..50be3091f23b0d0f7dbe9d86c544aed46ff6f288 100644 (file)
@@ -81,6 +81,14 @@ static THREAD_LOCAL uint8_t dechunk_buffer[65535];
             Server->response.header_norm_size = 0 ;\
             Server->response.cookie.cookie = NULL;\
             Server->response.cookie.cookie_end = NULL;\
+            if(Server->response.cookie.next) {\
+                COOKIE_PTR *cookie = Server->response.cookie.next; \
+                do { \
+                    Server->response.cookie.next = Server->response.cookie.next->next; \
+                    free(cookie); \
+                    cookie = Server->response.cookie.next; \
+                }while(cookie);\
+            }\
             Server->response.cookie.next = NULL;\
             Server->response.cookie_norm = NULL;\
             Server->response.cookie_norm_size = 0;\
@@ -167,7 +175,7 @@ static inline const u_char *MovePastDelims(const u_char *start, const u_char *en
 **  @retval HI_INVALID_ARG invalid argument
 **  @retval HI_SUCCESS     function success
 */
-static int IsHttpServerData(HI_SESSION *session, Packet *p, HttpsessionData *sd)
+static int IsHttpServerData(HI_SESSION *session, Packet *p, HttpSessionData *sd)
 {
     const u_char *start;
     const u_char *end;
@@ -330,7 +338,7 @@ static inline int hi_server_extract_status_code(
 
 /* Grab the argument of "charset=foo" from a Content-Type header */
 static inline const u_char *extract_http_content_type_charset(
-    HI_SESSION*, HttpsessionData *hsd,
+    HI_SESSION*, HttpSessionData *hsd,
     const u_char *p, const u_char*, const u_char *end )
 {
     size_t cmplen;
@@ -536,7 +544,7 @@ static inline const u_char *extract_http_content_encoding(HTTPINSPECT_CONF *Serv
 }
 
 const u_char *extract_http_transfer_encoding(
-    HI_SESSION*, HttpsessionData *hsd,
+    HI_SESSION*, HttpSessionData *hsd,
     const u_char *p, const u_char *start, const u_char *end,
     HEADER_PTR *header_ptr, int iInspectMode)
 {
@@ -595,7 +603,7 @@ const u_char *extract_http_transfer_encoding(
 static inline const u_char *extractHttpRespHeaderFieldValues(HTTPINSPECT_CONF *ServerConf,
         const u_char *p, const u_char *offset, const u_char *start,
         const u_char *end, HEADER_PTR *header_ptr,
-        HEADER_FIELD_PTR *header_field_ptr, int parse_cont_encoding, HttpsessionData *hsd,
+        HEADER_FIELD_PTR *header_field_ptr, int parse_cont_encoding, HttpSessionData *hsd,
         HI_SESSION *session)
 {
     if (((p - offset) == 0) && ((*p == 'S') || (*p == 's')))
@@ -646,7 +654,7 @@ static inline const u_char *hi_server_extract_header(
         HI_SESSION *session, HTTPINSPECT_CONF *ServerConf,
             HEADER_PTR *header_ptr, const u_char *start,
             const u_char *end, int parse_cont_encoding,
-            HttpsessionData *hsd)
+            HttpSessionData *hsd)
 {
     const u_char *p;
     const u_char *offset;
@@ -723,7 +731,7 @@ static inline const u_char *hi_server_extract_header(
 }
 
 static inline int hi_server_extract_body(
-                        HI_SESSION *session, HttpsessionData *sd,
+                        HI_SESSION *session, HttpSessionData *sd,
                         const u_char *ptr, const u_char *end, URI_PTR *result)
 {
     HTTPINSPECT_CONF *ServerConf;
@@ -809,7 +817,45 @@ static inline int hi_server_extract_body(
     return STAT_END;
 }
 
-static void SetGzipBuffers(HttpsessionData *hsd, HI_SESSION *session)
+static void LogFileDecomp(void*, int event)
+{
+    // FIXIT-H first argument is supposed to be pointer to session which may be needed to
+    // generate the event correctly.
+    hi_set_event(GID_HTTP_SERVER, event);
+}
+
+static void InitFileDecomp(HttpSessionData *hsd, HI_SESSION *session)
+{
+    fd_session_p_t fd_session;
+
+    if((hsd == NULL) || (session == NULL) || (session->server_conf == NULL) ||
+       (session->global_conf == NULL))
+        return;
+
+    if( (fd_session = File_Decomp_New()) == (fd_session_p_t)NULL )
+        return;
+
+    hsd->fd_state = fd_session;
+    fd_session->Modes = session->server_conf->file_decomp_modes;
+
+    fd_session->Alert_Callback = LogFileDecomp;
+    fd_session->Alert_Context = session;
+
+    if( (session->server_conf->unlimited_decompress) != 0 )
+    {
+        fd_session->Compr_Depth = 0;
+        fd_session->Decompr_Depth = 0;
+    }
+    else
+    {
+        fd_session->Compr_Depth = session->global_conf->compr_depth;
+        fd_session->Decompr_Depth = session->global_conf->decompr_depth;
+    }
+
+    (void)File_Decomp_Init( fd_session );
+}
+
+static void SetGzipBuffers(HttpSessionData *hsd, HI_SESSION *session)
 {
     if ((hsd != NULL) && (hsd->decomp_state == NULL)
             && (session != NULL) && (session->server_conf != NULL)
@@ -835,7 +881,7 @@ static void SetGzipBuffers(HttpsessionData *hsd, HI_SESSION *session)
 }
 
 int uncompress_gzip ( u_char *dest, int destLen, const u_char *source,
-        int sourceLen, HttpsessionData *sd, int *total_bytes_read, int compr_fmt)
+        int sourceLen, HttpSessionData *sd, int *total_bytes_read, int compr_fmt)
 {
     z_stream stream;
     int err;
@@ -909,7 +955,7 @@ int uncompress_gzip ( u_char *dest, int destLen, const u_char *source,
    {
 
        /* If some of the compressed data is decompressed we need to provide that for detection */
-       if( stream.total_out > 0)
+       if (( stream.total_out > 0) && (err != Z_DATA_ERROR))
        {
            *total_bytes_read = stream.total_out;
            iRet = HI_NONFATAL_ERR;
@@ -925,7 +971,7 @@ int uncompress_gzip ( u_char *dest, int destLen, const u_char *source,
    return HI_SUCCESS;
 }
 
-static inline int hi_server_decompress(HI_SESSION *session, HttpsessionData *sd, const u_char *ptr,
+static inline int hi_server_decompress(HI_SESSION *session, HttpSessionData *sd, const u_char *ptr,
         const u_char *end, URI_PTR *result)
 {
     const u_char *start = ptr;
@@ -983,6 +1029,7 @@ static inline int hi_server_decompress(HI_SESSION *session, HttpsessionData *sd,
 
     if ((compr_avail <= 0) || (decompr_avail <= 0))
     {
+        (void)File_Decomp_Reset(sd->fd_state);
         ResetGzipState(sd->decomp_state);
         ResetRespState(&(sd->resp_state));
         return iRet;
@@ -1052,6 +1099,7 @@ static inline int hi_server_decompress(HI_SESSION *session, HttpsessionData *sd,
         }
         else
             ResetRespState(&(sd->resp_state));
+        (void)File_Decomp_Reset(sd->fd_state);
         ResetGzipState(sd->decomp_state);
     }
 
@@ -1068,7 +1116,7 @@ static inline int hi_server_decompress(HI_SESSION *session, HttpsessionData *sd,
 
 }
 
-static inline int hi_server_inspect_body(HI_SESSION *session, HttpsessionData *sd, const u_char *ptr,
+static inline int hi_server_inspect_body(HI_SESSION *session, HttpSessionData *sd, const u_char *ptr,
                         const u_char *end, URI_PTR *result)
 {
     int iRet = HI_SUCCESS;
@@ -1079,6 +1127,7 @@ static inline int hi_server_inspect_body(HI_SESSION *session, HttpsessionData *s
     {
         if ((sd != NULL))
         {
+            (void)File_Decomp_Reset(sd->fd_state);
             ResetGzipState(sd->decomp_state);
             ResetRespState(&(sd->resp_state));
         }
@@ -1108,7 +1157,7 @@ static inline int hi_server_inspect_body(HI_SESSION *session, HttpsessionData *s
 }
 void ApplyFlowDepth(
     HTTPINSPECT_CONF *ServerConf, Packet *p,
-    HttpsessionData *sd, int resp_header_size, int, uint32_t seq_num)
+    HttpSessionData *sd, int resp_header_size, int, uint32_t seq_num)
 {
     if(!ServerConf->server_flow_depth)
     {
@@ -1167,14 +1216,15 @@ void ApplyFlowDepth(
     }
 }
 
-static inline void ResetState (HttpsessionData* sd)
+static inline void ResetState (HttpSessionData* sd)
 {
+    (void)File_Decomp_Reset(sd->fd_state);
     ResetGzipState(sd->decomp_state);
     ResetRespState(&(sd->resp_state));
 }
 
 static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned char *data,
-        int dsize, HttpsessionData *sd)
+        int dsize, HttpSessionData *sd)
 {
     HTTPINSPECT_CONF *ServerConf;
     URI_PTR stat_code_ptr;
@@ -1284,6 +1334,7 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
             }
             else
             {
+                (void)File_Decomp_Reset(sd->fd_state);
                 ResetGzipState(sd->decomp_state);
                 ResetRespState(&(sd->resp_state));
             }
@@ -1304,6 +1355,7 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
                 }
                 else
                 {
+                    (void)File_Decomp_Reset(sd->fd_state);
                     ResetGzipState(sd->decomp_state);
                     ResetRespState(&(sd->resp_state));
                 }
@@ -1317,6 +1369,7 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
                 }
                 else
                 {
+                    (void)File_Decomp_Reset(sd->fd_state);
                     ResetGzipState(sd->decomp_state);
                     ResetRespState(&(sd->resp_state));
                 }
@@ -1377,6 +1430,7 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
                 ApplyFlowDepth(ServerConf, p, sd, resp_header_size, 0, seq_num);
                 if ( not_stream_insert && (sd != NULL))
                 {
+                    (void)File_Decomp_Reset(sd->fd_state);
                     ResetGzipState(sd->decomp_state);
                     ResetRespState(&(sd->resp_state));
                 }
@@ -1396,6 +1450,7 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
                 expected_pkt = 0;
                 if(sd != NULL)
                 {
+                    (void)File_Decomp_Reset(sd->fd_state);
                     ResetGzipState(sd->decomp_state);
                     ResetRespState(&(sd->resp_state));
                     sd->resp_state.flow_depth_excd = false;
@@ -1512,6 +1567,11 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
                             sd->resp_state.inspect_body = 1;
                         }
 
+                        if( ServerConf->file_decomp_modes != 0 )
+                        {
+                            InitFileDecomp(sd, session);
+                        }
+
                         sd->resp_state.last_pkt_contlen = (header_ptr.content_len.len != 0);
                         if(ServerConf->server_flow_depth == -1)
                             sd->resp_state.flow_depth_excd = true;
@@ -1580,8 +1640,13 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
             {
                 status = SafeMemcpy(HttpDecodeBuf.data, Server->response.body,
                                             alt_dsize, HttpDecodeBuf.data, HttpDecodeBuf.data + sizeof(HttpDecodeBuf.data));
-                if( status != SAFEMEM_SUCCESS  )
+                if (status != SAFEMEM_SUCCESS)
+                {
+                    CLR_SERVER_HEADER(Server);
+                    CLR_SERVER_STAT_MSG(Server);
+                    CLR_SERVER_STAT(Server);
                     return HI_MEM_ALLOC_FAIL;
+                }
 
                 SetHttpDecode((uint16_t)alt_dsize);
                 Server->response.body = HttpDecodeBuf.data;
@@ -1619,17 +1684,11 @@ static int HttpResponseInspection(HI_SESSION *session, Packet *p, const unsigned
         }
 
     }
-    {
-        /* There is no body to the HTTP response.
-         * In this case we need to inspect the entire HTTP response header.
-         */
-        ApplyFlowDepth(ServerConf, p, sd, resp_header_size, 1, seq_num);
-    }
-
+    ApplyFlowDepth(ServerConf, p, sd, resp_header_size, 1, seq_num);
     return HI_SUCCESS;
 }
 
-int ServerInspection(HI_SESSION *session, Packet *p, HttpsessionData *hsd)
+int ServerInspection(HI_SESSION *session, Packet *p, HttpSessionData *hsd)
 {
     int iRet;
 
@@ -1655,7 +1714,7 @@ int ServerInspection(HI_SESSION *session, Packet *p, HttpsessionData *hsd)
     return HI_SUCCESS;
 }
 
-int hi_server_inspection(void *S, Packet *p, HttpsessionData *hsd)
+int hi_server_inspection(void *S, Packet *p, HttpSessionData *hsd)
 {
     HI_SESSION *session;
 
index 19e88e7416b49fe4a0edf71084efd0573570434f..6e5ea8ea6c3f5b2301c1c883a0599ba55957d4cb 100644 (file)
@@ -66,7 +66,7 @@ typedef struct s_HI_SERVER
     HI_SERVER_RESP response;
 } HI_SERVER;
 
-int hi_server_inspection(void *, Packet *, HttpsessionData *);
+int hi_server_inspection(void *, Packet *, HttpSessionData *);
 
 #endif
 
index c28722bc7858a0daf55246eb3bec141c3cb684d7..3d74d54dcd269588a0f6243af46437c00c954133 100644 (file)
@@ -57,7 +57,7 @@
 #include "detection_util.h"
 
 
-int hi_server_norm(HI_SESSION *session, HttpsessionData *hsd)
+int hi_server_norm(HI_SESSION *session, HttpSessionData *hsd)
 {
     static THREAD_LOCAL u_char HeaderBuf[MAX_URI];
     static THREAD_LOCAL u_char CookieBuf[MAX_URI];
index eb8886cf302ed5016c981bc6ebb487723bc54d47..4775f0b54e3fbf6706f31d6809178d1a88f7ccb9 100644 (file)
@@ -35,6 +35,6 @@
 #include "hi_include.h"
 #include "hi_si.h"
 
-int hi_server_norm(HI_SESSION *session, HttpsessionData *hsd);
+int hi_server_norm(HI_SESSION *session, HttpSessionData *hsd);
 
 #endif
index cc47df5a7b7748a2203bf6a3adfccdde9e0d1c12..046d89d795d3d11d058c6be07bea17cf2087ba0c 100644 (file)
@@ -121,12 +121,12 @@ int hi_si_session_inspection(HTTPINSPECT_CONF *GlobalConf,
         Packet *p);
 
 extern int CheckChunkEncoding(HI_SESSION *, const u_char *, const u_char *, const u_char **, u_char *,
-                              uint32_t , uint32_t, uint32_t *, uint32_t *, HttpsessionData *, int);
+                              uint32_t , uint32_t, uint32_t *, uint32_t *, HttpSessionData *, int);
 extern int IsHttpVersion(const u_char **, const u_char *);
 extern const u_char *extract_http_cookie(const u_char *p, const u_char *end, HEADER_PTR *, HEADER_FIELD_PTR *);
 extern const u_char *extract_http_content_length(HI_SESSION *, HTTPINSPECT_CONF *, const u_char *, const u_char *, const u_char *, HEADER_PTR *, HEADER_FIELD_PTR *) ;
 
-extern const u_char *extract_http_transfer_encoding(HI_SESSION *, HttpsessionData *,
+extern const u_char *extract_http_transfer_encoding(HI_SESSION *, HttpSessionData *,
         const u_char *, const u_char *, const u_char *, HEADER_PTR *, int);
 #endif
 
index 5e1fec198827473d78633c23e841bcd0aa70691f..99d8da715e70dc66265f698d1f00973f07b44cda 100644 (file)
@@ -39,6 +39,7 @@
 #include "sf_ip.h"
 #include "hi_util_kmap.h"
 #include "file_api/file_api.h"
+#include "hi_file_decomp.h"
 #include "framework/bits.h"
 
 /*
@@ -47,6 +48,7 @@
 #define HI_UI_CONFIG_MAX_HDR_DEFAULT 0
 #define HI_UI_CONFIG_MAX_HEADERS_DEFAULT 0
 #define HI_UI_CONFIG_MAX_SPACES_DEFAULT 200 
+#define HI_UI_CONFIG_MAX_XFF_FIELD_NAMES 8
 
 /*
 **  Special characters treated as whitespace before or after URI
@@ -152,11 +154,20 @@ struct HTTPINSPECT_CONF
     char uri_only;
     char enable_cookie;
     char inspect_response;
+    uint8_t *xff_headers[HI_UI_CONFIG_MAX_XFF_FIELD_NAMES];
+    uint8_t xff_header_lengths[HI_UI_CONFIG_MAX_XFF_FIELD_NAMES];
     char enable_xff;
     char log_uri;
     char log_hostname;
     bool unlimited_decompress;
     char extract_gzip;
+    unsigned long file_decomp_modes;
+
+/* NOTE:  The XFF_BUILTING_NAMES value must match the code in snort_httpinspect.c that
+          adds the builtin names to the list. */
+#define HI_UI_CONFIG_XFF_FIELD_NAME  "X-Forwarded-For"
+#define HI_UI_CONFIG_TCI_FIELD_NAME  "True-Client-IP"
+#define XFF_BUILTIN_NAMES            (2)
 
    /* Support Extended ascii codes in the URI */
     char extended_ascii_uri;
index c18a661b2c657fe44c609b7d1cd7e80f117e5838..30fec34506f9fc99c2bb519a6a173405b819e09d 100644 (file)
@@ -47,6 +47,7 @@
 #include "snort_debug.h"
 #include "util.h"
 #include "parser.h"
+#include "hi_file_decomp.h"
 
 #include "hi_client.h"
 #include "hi_ui_config.h"
@@ -70,8 +71,6 @@
 #include "framework/inspector.h"
 #include "managers/data_manager.h"
 
-#define ERRSTRLEN 1000
-
 int hex_lookup[256];
 int valid_lookup[256];
 
@@ -127,7 +126,7 @@ static void CheckGzipConfig(HTTPINSPECT_GLOBAL_CONF *pPolicyConfig)
         pPolicyConfig->decompr_depth = DEFAULT_DECOMP_DEPTH;
 
     pPolicyConfig->max_gzip_sessions =
-        pPolicyConfig->max_gzip_mem / sizeof(DECOMPRESS_STATE);
+        pPolicyConfig->max_gzip_mem / (sizeof(DECOMPRESS_STATE) + sizeof(fd_session_t));
 }
 
 static void CheckMemcap(HTTPINSPECT_GLOBAL_CONF *pPolicyConfig)