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