1 /****************************************************************************
2  *
3  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4  * Copyright (C) 2003-2013 Sourcefire, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License Version 2 as
8  * published by the Free Software Foundation.  You may not use, modify or
9  * distribute this program under any other version of the GNU General
10  * Public License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *
21  ****************************************************************************/
22 
23 /**
24 **  @file       hi_eo_log.c
25 **
26 **  @author     Daniel Roelker <droelker@sourcefire.com>
27 **
28 **  @brief      This file contains the event output functionality that
29 **              HttpInspect uses to log events and data associated with
30 **              the events.
31 **
32 **  Log events, retrieve events, and select events that HttpInspect
33 **  generates.
34 **
35 **  Logging Events:
36 **    Since the object behind this is no memset()s, we have to rely on the
37 **    stack interface to make sure we don't log the same event twice.  So
38 **    if there are events in the stack we cycle through to make sure that
39 **    there are none available before we add a new event and increment the
40 **    stack count.  Then to reset the event queue, we just need to set the
41 **    stack count back to zero.
42 **
43 **  NOTES:
44 **    - Initial development.  DJR
45 */
46 #include <stdlib.h>
47 
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 
52 #include "hi_si.h"
53 #include "hi_eo.h"
54 #include "hi_util_xmalloc.h"
55 #include "hi_return_codes.h"
56 
57 /*
58 **  The client events and the priorities are listed here.
59 **  Any time that a new client event is added, we have to
60 **  add the event id and the priority here.  If you want to
61 **  change either of those characteristics, you have to change
62 **  them here.
63 */
64 static HI_EVENT_INFO client_event_info[HI_EO_CLIENT_EVENT_NUM] = {
65     { HI_EO_CLIENT_ASCII, HI_EO_LOW_PRIORITY, HI_EO_CLIENT_ASCII_STR },
66     { HI_EO_CLIENT_DOUBLE_DECODE, HI_EO_HIGH_PRIORITY,
67         HI_EO_CLIENT_DOUBLE_DECODE_STR },
68     { HI_EO_CLIENT_U_ENCODE, HI_EO_MED_PRIORITY, HI_EO_CLIENT_U_ENCODE_STR },
69     { HI_EO_CLIENT_BARE_BYTE, HI_EO_HIGH_PRIORITY, HI_EO_CLIENT_BARE_BYTE_STR},
70     /* Base36 is deprecated - leave here so events keep the same number */
71     { HI_EO_CLIENT_BASE36, HI_EO_HIGH_PRIORITY, HI_EO_CLIENT_BASE36_STR },
72     { HI_EO_CLIENT_UTF_8, HI_EO_LOW_PRIORITY, HI_EO_CLIENT_UTF_8_STR },
73     { HI_EO_CLIENT_IIS_UNICODE, HI_EO_LOW_PRIORITY,
74         HI_EO_CLIENT_IIS_UNICODE_STR },
75     { HI_EO_CLIENT_MULTI_SLASH, HI_EO_MED_PRIORITY,
76         HI_EO_CLIENT_MULTI_SLASH_STR },
77     { HI_EO_CLIENT_IIS_BACKSLASH, HI_EO_MED_PRIORITY,
78         HI_EO_CLIENT_IIS_BACKSLASH_STR },
79     { HI_EO_CLIENT_SELF_DIR_TRAV, HI_EO_HIGH_PRIORITY,
80         HI_EO_CLIENT_SELF_DIR_TRAV_STR },
81     { HI_EO_CLIENT_DIR_TRAV, HI_EO_LOW_PRIORITY, HI_EO_CLIENT_DIR_TRAV_STR },
82     { HI_EO_CLIENT_APACHE_WS, HI_EO_MED_PRIORITY, HI_EO_CLIENT_APACHE_WS_STR },
83     { HI_EO_CLIENT_IIS_DELIMITER, HI_EO_MED_PRIORITY,
84         HI_EO_CLIENT_IIS_DELIMITER_STR },
85     { HI_EO_CLIENT_NON_RFC_CHAR, HI_EO_HIGH_PRIORITY,
86         HI_EO_CLIENT_NON_RFC_CHAR_STR },
87     { HI_EO_CLIENT_OVERSIZE_DIR, HI_EO_HIGH_PRIORITY,
88         HI_EO_CLIENT_OVERSIZE_DIR_STR },
89     {HI_EO_CLIENT_LARGE_CHUNK, HI_EO_HIGH_PRIORITY,
90         HI_EO_CLIENT_LARGE_CHUNK_STR },
91     {HI_EO_CLIENT_PROXY_USE, HI_EO_LOW_PRIORITY,
92         HI_EO_CLIENT_PROXY_USE_STR },
93     {HI_EO_CLIENT_WEBROOT_DIR, HI_EO_HIGH_PRIORITY,
94         HI_EO_CLIENT_WEBROOT_DIR_STR },
95     {HI_EO_CLIENT_LONG_HDR, HI_EO_LOW_PRIORITY,
96         HI_EO_CLIENT_LONG_HDR_STR},
97     {HI_EO_CLIENT_MAX_HEADERS, HI_EO_LOW_PRIORITY,
98         HI_EO_CLIENT_MAX_HEADERS_STR},
99     {HI_EO_CLIENT_MULTIPLE_CONTLEN, HI_EO_HIGH_PRIORITY,
100         HI_EO_CLIENT_MULTIPLE_CONTLEN_STR},
101     {HI_EO_CLIENT_CHUNK_SIZE_MISMATCH, HI_EO_HIGH_PRIORITY,
102         HI_EO_CLIENT_CHUNK_SIZE_MISMATCH_STR},
103     {HI_EO_CLIENT_INVALID_TRUEIP, HI_EO_LOW_PRIORITY,
104         HI_EO_CLIENT_INVALID_TRUEIP_STR},
105     {HI_EO_CLIENT_MULTIPLE_HOST_HDRS, HI_EO_LOW_PRIORITY,
106         HI_EO_CLIENT_MULTIPLE_HOST_HDRS_STR},
107     {HI_EO_CLIENT_LONG_HOSTNAME, HI_EO_LOW_PRIORITY,
108         HI_EO_CLIENT_LONG_HOSTNAME_STR},
109     {HI_EO_CLIENT_EXCEEDS_SPACES, HI_EO_LOW_PRIORITY,
110         HI_EO_CLIENT_EXCEEDS_SPACES_STR},
111     {HI_EO_CLIENT_CONSECUTIVE_SMALL_CHUNKS, HI_EO_MED_PRIORITY,
112         HI_EO_CLIENT_CONSECUTIVE_SMALL_CHUNKS_STR},
113     {HI_EO_CLIENT_UNBOUNDED_POST, HI_EO_MED_PRIORITY,
114         HI_EO_CLIENT_UNBOUNDED_POST_STR},
115     {HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION, HI_EO_MED_PRIORITY,
116         HI_EO_CLIENT_MULTIPLE_TRUEIP_IN_SESSION_STR},
117     {HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS, HI_EO_LOW_PRIORITY,
118         HI_EO_CLIENT_BOTH_TRUEIP_XFF_HDRS_STR},
119     {HI_EO_CLIENT_UNKNOWN_METHOD, HI_EO_MED_PRIORITY,
120         HI_EO_CLIENT_UNKNOWN_METHOD_STR},
121     {HI_EO_CLIENT_SIMPLE_REQUEST, HI_EO_HIGH_PRIORITY,
122         HI_EO_CLIENT_SIMPLE_REQUEST_STR},
123     {HI_EO_CLIENT_UNESCAPED_SPACE_URI, HI_EO_MED_PRIORITY,
124             HI_EO_CLIENT_UNESCAPED_SPACE_URI_STR},
125     {HI_EO_CLIENT_PIPELINE_MAX, HI_EO_MED_PRIORITY,
126         HI_EO_CLIENT_PIPELINE_MAX_STR},
127     {HI_EO_CLIENT_MULTIPLE_COLON_BETN_KEY_VALUE, HI_EO_HIGH_PRIORITY,
128         HI_EO_CLIENT_MULTIPLE_COLON_BETN_KEY_VALUE_STR},
129     {HI_EO_CLIENT_INVALID_RANGE_UNIT_FMT, HI_EO_MED_PRIORITY,
130         HI_EO_CLIENT_INVALID_RANGE_UNIT_FMT_STR},
131     {HI_EO_CLIENT_RANGE_NON_GET_METHOD, HI_EO_MED_PRIORITY,
132         HI_EO_CLIENT_RANGE_NON_GET_METHOD_STR},
133     {HI_EO_CLIENT_RANGE_FIELD_ERROR, HI_EO_MED_PRIORITY,
134         HI_EO_CLIENT_RANGE_FIELD_ERROR_STR}
135 };
136 
137 static HI_EVENT_INFO server_event_info[HI_EO_SERVER_EVENT_NUM] = {
138     {HI_EO_ANOM_SERVER, HI_EO_HIGH_PRIORITY, HI_EO_ANOM_SERVER_STR },
139     {HI_EO_SERVER_INVALID_STATCODE, HI_EO_MED_PRIORITY,
140                     HI_EO_SERVER_INVALID_STATCODE_STR},
141     {HI_EO_SERVER_NO_CONTLEN, HI_EO_MED_PRIORITY,
142         HI_EO_SERVER_NO_CONTLEN_STR},
143     {HI_EO_SERVER_UTF_NORM_FAIL, HI_EO_MED_PRIORITY,
144         HI_EO_SERVER_UTF_NORM_FAIL_STR},
145     {HI_EO_SERVER_UTF7, HI_EO_MED_PRIORITY,
146         HI_EO_SERVER_UTF7_STR},
147     {HI_EO_SERVER_DECOMPR_FAILED, HI_EO_MED_PRIORITY,
148         HI_EO_SERVER_DECOMPR_FAILED_STR},
149     {HI_EO_SERVER_CONSECUTIVE_SMALL_CHUNKS, HI_EO_MED_PRIORITY,
150         HI_EO_SERVER_CONSECUTIVE_SMALL_CHUNKS_STR},
151     {HI_EO_CLISRV_MSG_SIZE_EXCEPTION, HI_EO_MED_PRIORITY,
152         HI_EO_CLISRV_MSG_SIZE_EXCEPTION_STR},
153     {HI_EO_SERVER_JS_OBFUSCATION_EXCD, HI_EO_MED_PRIORITY,
154         HI_EO_SERVER_JS_OBFUSCATION_EXCD_STR},
155     {HI_EO_SERVER_JS_EXCESS_WS, HI_EO_MED_PRIORITY,
156         HI_EO_SERVER_JS_EXCESS_WS_STR},
157     {HI_EO_SERVER_MIXED_ENCODINGS, HI_EO_MED_PRIORITY,
158         HI_EO_SERVER_MIXED_ENCODINGS_STR},
159     {HI_EO_SERVER_SWF_ZLIB_FAILURE, HI_EO_MED_PRIORITY,
160         HI_EO_SERVER_SWF_ZLIB_FAILURE_STR},
161     {HI_EO_SERVER_SWF_LZMA_FAILURE, HI_EO_MED_PRIORITY,
162         HI_EO_SERVER_SWF_LZMA_FAILURE_STR},
163     {HI_EO_SERVER_PDF_DEFL_FAILURE, HI_EO_MED_PRIORITY,
164         HI_EO_SERVER_PDF_DEFL_FAILURE_STR},
165     {HI_EO_SERVER_PDF_UNSUP_COMP_TYPE, HI_EO_MED_PRIORITY,
166         HI_EO_SERVER_PDF_UNSUP_COMP_TYPE_STR},
167     {HI_EO_SERVER_PDF_CASC_COMP, HI_EO_MED_PRIORITY,
168         HI_EO_SERVER_PDF_CASC_COMP_STR},
169     {HI_EO_SERVER_PDF_PARSE_FAILURE, HI_EO_MED_PRIORITY,
170         HI_EO_SERVER_PDF_PARSE_FAILURE_STR},
171     {HI_EO_SERVER_PROTOCOL_OTHER, HI_EO_MED_PRIORITY,
172         HI_EO_SERVER_PROTOCOL_OTHER_STR},
173     {HI_EO_SERVER_MULTIPLE_CONTLEN, HI_EO_HIGH_PRIORITY,
174         HI_EO_SERVER_MULTIPLE_CONTLEN_STR},
175     {HI_EO_SERVER_MULTIPLE_CONTENT_ENCODING, HI_EO_HIGH_PRIORITY,
176         HI_EO_SERVER_MULTIPLE_CONTENT_ENCODING_STR},
177     {HI_EO_SERVER_MULTIPLE_COLON_BETN_KEY_VALUE, HI_EO_HIGH_PRIORITY,
178         HI_EO_SERVER_MULTIPLE_COLON_BETN_KEY_VALUE_STR},
179     {HI_EO_SERVER_INVALID_CHAR_BETN_KEY_VALUE, HI_EO_HIGH_PRIORITY,
180         HI_EO_SERVER_INVALID_CHAR_BETN_KEY_VALUE_STR},
181     {HI_EO_CLISRV_INVALID_CHUNKED_ENCODING, HI_EO_HIGH_PRIORITY,
182         HI_EO_CLISRV_INVALID_CHUNKED_EXCEPTION_STR},
183     {HI_EO_SERVER_PARTIAL_DECOMPRESSION_FAIL, HI_EO_HIGH_PRIORITY,
184         HI_EO_SERVER_PARTIAL_DECOMPRESSION_FAIL_STR},
185     {HI_EO_SERVER_INVALID_HEADER_FOLDING, HI_EO_HIGH_PRIORITY,
186         HI_EO_SERVER_INVALID_HEADER_FOLDING_STR},
187     {HI_EO_SERVER_JUNK_LINE_BEFORE_RESP_HEADER,HI_EO_HIGH_PRIORITY,
188         HI_EO_SERVER_JUNK_LINE_BEFORE_RESP_HEADER_STR},
189     {HI_EO_SERVER_NO_RESP_HEADER_END,HI_EO_HIGH_PRIORITY,
190         HI_EO_SERVER_NO_RESP_HEADER_END_STR},
191     {HI_EO_SERVER_INVALID_CHUNK_SIZE,HI_EO_HIGH_PRIORITY,
192         HI_EO_SERVER_INVALID_CHUNK_SIZE_STR},
193     {HI_EO_SERVER_INVALID_VERSION_RESP_HEADER,HI_EO_HIGH_PRIORITY,
194         HI_EO_SERVER_INVALID_VERSION_RESP_HEADER_STR},
195     {HI_EO_SERVER_INVALID_CONTENT_RANGE_UNIT_FMT, HI_EO_MED_PRIORITY,
196         HI_EO_SERVER_INVALID_CONTENT_RANGE_UNIT_FMT_STR},
197     {HI_EO_SERVER_RANGE_FIELD_ERROR, HI_EO_MED_PRIORITY,
198         HI_EO_SERVER_RANGE_FIELD_ERROR_STR},
199     {HI_EO_SERVER_NON_RANGE_GET_PARTIAL_METHOD, HI_EO_MED_PRIORITY,
200         HI_EO_SERVER_NON_RANGE_GET_PARTIAL_METHOD_STR}
201 };
202 
203 /*
204 **  hi_eo_anom_server_event_log::
205 */
206 /**
207 **  This routine logs anomalous server events to the event queue.
208 **
209 **  @param Session   pointer to the HttpInspect session
210 **  @param iEvent    the event id for the client
211 **  @param data      pointer to the user data of the event
212 **  @param free_data pointer to a function to free the user data
213 **
214 **  @return integer
215 **
216 **  @retval HI_SUCCESS function successful
217 **  @retval HI_INVALID_ARG invalid arguments
218 */
hi_eo_anom_server_event_log(HI_SESSION * Session,int iEvent,void * data,void (* free_data)(void *))219 int hi_eo_anom_server_event_log(HI_SESSION *Session, int iEvent, void *data,
220         void (*free_data)(void *))
221 {
222     HI_ANOM_SERVER_EVENTS *anom_server_events;
223     HI_EVENT *event;
224     int iCtr;
225 
226     /*
227     **  Check the input variables for correctness
228     */
229     if(!Session || (iEvent >= HI_EO_SERVER_EVENT_NUM))
230     {
231         return HI_INVALID_ARG;
232     }
233 
234     anom_server_events = &(Session->anom_server.event_list);
235 
236     /* this won't happen since iEvent < HI_EO_SERVER_EVENT_NUM and
237      * stack_count can at most equal HI_EO_SERVER_EVENT_NUM */
238     if (anom_server_events->stack_count > HI_EO_SERVER_EVENT_NUM)
239         return HI_INVALID_ARG;
240 
241     /*
242     **  This is where we cycle through the current event stack.  If the event
243     **  to be logged is already in the queue, then we increment the event
244     **  count, before returning.  Otherwise, we fall through the loop and
245     **  set the event before adding it to the queue and incrementing the
246     **  pointer.
247     */
248     for(iCtr = 0; iCtr < anom_server_events->stack_count; iCtr++)
249     {
250         if(anom_server_events->stack[iCtr] == iEvent)
251         {
252             anom_server_events->events[iEvent].count++;
253             return HI_SUCCESS;
254         }
255     }
256 
257     /* this won't happen since iEvent will have been found above
258      * before this happens */
259     if (anom_server_events->stack_count >= HI_EO_SERVER_EVENT_NUM)
260         return HI_INVALID_ARG;
261 
262     /*
263     **  Initialize the event before putting it in the queue.
264     */
265     event = &(anom_server_events->events[iEvent]);
266     event->event_info = &server_event_info[iEvent];
267     event->count = 1;
268     event->data = data;
269     event->free_data = free_data;
270 
271     /*
272     **  We now add the event to the stack.
273     */
274     anom_server_events->stack[anom_server_events->stack_count] = iEvent;
275     anom_server_events->stack_count++;
276 
277     return HI_SUCCESS;
278 }
279 
280 /*
281 **  NAME
282 **    hi_eo_client_event_log::
283 */
284 /**
285 **  This function logs client events during HttpInspect processing.
286 **
287 **  The idea behind this event logging is modularity, but at the same time
288 **  performance.  We accomplish this utilizing an optimized stack as an
289 **  index into the client event array, instead of walking a list for
290 **  already logged events.  The problem here is that we can't just log
291 **  every event that we've already seen, because this opens us up to a
292 **  DOS.  So by using this method, we can quickly check if an event
293 **  has already been logged and deal appropriately.
294 **
295 **  @param Session   pointer to the HttpInspect session
296 **  @param iEvent    the event id for the client
297 **  @param data      pointer to the user data of the event
298 **  @param free_data pointer to a function to free the user data
299 **
300 **  @return integer
301 **
302 **  @retval HI_SUCCESS function successful
303 **  @retval HI_INVALID_ARG invalid arguments
304 */
hi_eo_client_event_log(HI_SESSION * Session,int iEvent,void * data,void (* free_data)(void *))305 int hi_eo_client_event_log(HI_SESSION *Session, int iEvent, void *data,
306         void (*free_data)(void *))
307 {
308     HI_CLIENT_EVENTS *client_events;
309     HI_EVENT *event;
310     int iCtr;
311 
312     /*
313     **  Check the input variables for correctness
314     */
315     if(!Session || (iEvent >= HI_EO_CLIENT_EVENT_NUM))
316     {
317         return HI_INVALID_ARG;
318     }
319 
320     client_events = &(Session->client.event_list);
321 
322     /*
323     **  This is where we cycle through the current event stack.  If the event
324     **  to be logged is already in the queue, then we increment the event
325     **  count, before returning.  Otherwise, we fall through the loop and
326     **  set the event before adding it to the queue and incrementing the
327     **  pointer.
328     */
329     for(iCtr = 0; iCtr < client_events->stack_count; iCtr++)
330     {
331         if(client_events->stack[iCtr] == iEvent)
332         {
333             client_events->events[iEvent].count++;
334             return HI_SUCCESS;
335         }
336     }
337 
338     /*
339     **  Initialize the event before putting it in the queue.
340     */
341     event = &(client_events->events[iEvent]);
342     event->event_info = &client_event_info[iEvent];
343     event->count = 1;
344     event->data = data;
345     event->free_data = free_data;
346 
347     /*
348     **  We now add the event to the stack.
349     */
350     client_events->stack[client_events->stack_count] = iEvent;
351     client_events->stack_count++;
352 
353     return HI_SUCCESS;
354 }
355 
356 /*
357 **  NAME
358 **    hi_eo_server_event_log::
359 */
360 /**
361 **  This function logs server events during HttpInspect processing.
362 **
363 **  The idea behind this event logging is modularity, but at the same time
364 **  performance.  We accomplish this utilizing an optimized stack as an
365 **  index into the server event array, instead of walking a list for
366 **  already logged events.  The problem here is that we can't just log
367 **  every event that we've already seen, because this opens us up to a
368 **  DOS.  So by using this method, we can quickly check if an event
369 **  has already been logged and deal appropriately.
370 **
371 **  @param Session   pointer to the HttpInspect session
372 **  @param iEvent    the event id for the server
373 **  @param data      pointer to the user data of the event
374 **  @param free_data pointer to a function to free the user data
375 **
376 **  @return integer
377 **
378 **  @retval HI_SUCCESS function successful
379 **  @retval HI_INVALID_ARG invalid arguments
380 */
hi_eo_server_event_log(HI_SESSION * Session,int iEvent,void * data,void (* free_data)(void *))381 int hi_eo_server_event_log(HI_SESSION *Session, int iEvent, void *data,
382         void (*free_data)(void *))
383 {
384     HI_SERVER_EVENTS *server_events;
385     HI_EVENT *event;
386     int iCtr;
387 
388     /*
389     **  Check the input variables for correctness
390     */
391     if(!Session || (iEvent >= HI_EO_SERVER_EVENT_NUM))
392     {
393         return HI_INVALID_ARG;
394     }
395 
396     server_events = &(Session->server.event_list);
397 
398     /*
399     **  This is where we cycle through the current event stack.  If the event
400     **  to be logged is already in the queue, then we increment the event
401     **  count, before returning.  Otherwise, we fall through the loop and
402     **  set the event before adding it to the queue and incrementing the
403     **  pointer.
404     */
405     for(iCtr = 0; iCtr < server_events->stack_count; iCtr++)
406     {
407         if(server_events->stack[iCtr] == iEvent)
408         {
409             server_events->events[iEvent].count++;
410             return HI_SUCCESS;
411         }
412     }
413 
414     /*
415     **  Initialize the event before putting it in the queue.
416     */
417     event = &(server_events->events[iEvent]);
418     event->event_info = &server_event_info[iEvent];
419     event->count = 1;
420     event->data = data;
421     event->free_data = free_data;
422 
423     /*
424     **  We now add the event to the stack.
425     */
426     server_events->stack[server_events->stack_count] = iEvent;
427     server_events->stack_count++;
428 
429     return HI_SUCCESS;
430 }
431