1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2011-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 *
25 * spp_imap.c
26 *
27 * Author: Bhagyashree Bantwal <bbantwal@cisco.com>
28 *
29 * Description:
30 *
31 * This file initializes IMAP as a Snort preprocessor.
32 *
33 * This file registers the IMAP initialization function,
34 * adds the IMAP function into the preprocessor list.
35 *
36 * In general, this file is a wrapper to IMAP functionality,
37 * by interfacing with the Snort preprocessor functions. The rest
38 * of IMAP should be separate from the preprocessor hooks.
39 *
40 **************************************************************************/
41
42 #include <assert.h>
43 #include <sys/types.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46 #include <string.h>
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include "sf_types.h"
53 #include "spp_imap.h"
54 #include "sf_preproc_info.h"
55 #include "snort_imap.h"
56 #include "imap_util.h"
57 #include "imap_config.h"
58 #include "imap_log.h"
59 #include "imap_paf.h"
60
61 #include "preprocids.h"
62 #include "sf_snort_packet.h"
63 #include "sf_dynamic_preprocessor.h"
64 #include "snort_debug.h"
65 #include "sfPolicy.h"
66 #include "sfPolicyUserData.h"
67
68 #include "profiler.h"
69 #ifdef PERF_PROFILING
70 PreprocStats imapPerfStats;
71 PreprocStats imapDetectPerfStats;
72 int imapDetectCalled = 0;
73 #endif
74
75 #include "sf_types.h"
76 #include "mempool.h"
77 #include "snort_bounds.h"
78
79 #include "file_api.h"
80 #ifdef REG_TEST
81 #include "reg_test.h"
82 #endif
83
84 #ifdef DUMP_BUFFER
85 #include "imap_buffer_dump.h"
86 #endif
87
88 const int MAJOR_VERSION = 1;
89 const int MINOR_VERSION = 0;
90 const int BUILD_VERSION = 1;
91 const char *PREPROC_NAME = "SF_IMAP";
92 const char *PROTOCOL_NAME = "IMAP";
93
94 #define SetupIMAP DYNAMIC_PREPROC_SETUP
95
96 MemPool *imap_mempool = NULL;
97 MemPool *imap_mime_mempool = NULL;
98
99 IMAP_Stats imap_stats;
100
101 tSfPolicyUserContextId imap_config = NULL;
102 IMAPConfig *imap_eval_config = NULL;
103
104 extern int16_t imap_proto_id;
105
106 static void IMAPInit(struct _SnortConfig *, char *);
107 static void IMAPDetect(void *, void *context);
108 static void IMAPCleanExitFunction(int, void *);
109 static void IMAPResetFunction(int, void *);
110 static void IMAPResetStatsFunction(int, void *);
111 static void registerPortsForDispatch( struct _SnortConfig *sc, IMAPConfig *policy );
112 static void registerPortsForReassembly( IMAPConfig *policy, int direction );
113 static void _addPortsToStreamFilter(struct _SnortConfig *, IMAPConfig *, tSfPolicyId);
114 static void IMAP_PrintStats(int);
115 #ifdef TARGET_BASED
116 static void _addServicesToStreamFilter(struct _SnortConfig *, tSfPolicyId);
117 #endif
118 static int IMAPCheckConfig(struct _SnortConfig *);
119
120 #ifdef SNORT_RELOAD
121 static int IMAPMempoolFreeUsedBucket(MemPool *memory_pool);
122 static unsigned IMAPReloadMimeMempoolAdjust(unsigned imapMaxWork);
123 static unsigned IMAPReloadLogMempoolAdjust(unsigned imapMaxWork);
124 static bool IMAPMimeReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
125 static bool IMAPLogReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData);
126 static void IMAPReload(struct _SnortConfig *, char *, void **);
127 static int IMAPReloadVerify(struct _SnortConfig *, void *);
128 static void * IMAPReloadSwap(struct _SnortConfig *, void *);
129 static void IMAPReloadSwapFree(void *);
130 #endif
131
132
133 /*
134 * Function: SetupIMAP()
135 *
136 * Purpose: Registers the preprocessor keyword and initialization
137 * function into the preprocessor list. This is the function that
138 * gets called from InitPreprocessors() in plugbase.c.
139 *
140 * Arguments: None.
141 *
142 * Returns: void function
143 *
144 */
SetupIMAP(void)145 void SetupIMAP(void)
146 {
147 /* link the preprocessor keyword to the init function in the preproc list */
148 #ifndef SNORT_RELOAD
149 _dpd.registerPreproc("imap", IMAPInit);
150 #else
151 _dpd.registerPreproc("imap", IMAPInit, IMAPReload,
152 IMAPReloadVerify, IMAPReloadSwap, IMAPReloadSwapFree);
153 #endif
154 #ifdef DUMP_BUFFER
155 _dpd.registerBufferTracer(getIMAPBuffers, IMAP_BUFFER_DUMP_FUNC);
156 #endif
157
158 }
159
160 #ifdef REG_TEST
PrintIMAPSize(void)161 static inline void PrintIMAPSize(void)
162 {
163 _dpd.logMsg("\nIMAP Session Size: %lu\n", (long unsigned int)sizeof(IMAP));
164 }
165 #endif
166
167 /*
168 * Function: IMAPInit(char *)
169 *
170 * Purpose: Calls the argument parsing function, performs final setup on data
171 * structs, links the preproc function into the function list.
172 *
173 * Arguments: args => ptr to argument string
174 *
175 * Returns: void function
176 *
177 */
IMAPInit(struct _SnortConfig * sc,char * args)178 static void IMAPInit(struct _SnortConfig *sc, char *args)
179 {
180 IMAPToken *tmp;
181 tSfPolicyId policy_id = _dpd.getParserPolicy(sc);
182 IMAPConfig * pPolicyConfig = NULL;
183
184 #ifdef REG_TEST
185 PrintIMAPSize();
186 #endif
187
188 _dpd.registerMemoryStatsFunc(PP_IMAP, IMAP_Print_Mem_Stats);
189
190 if (imap_config == NULL)
191 {
192 //create a context
193 imap_config = sfPolicyConfigCreate();
194 if (imap_config == NULL)
195 {
196 DynamicPreprocessorFatalMessage("Not enough memory to create IMAP "
197 "configuration.\n");
198 }
199
200 /* Initialize the searches not dependent on configuration.
201 * headers, reponsed, data, mime boundary regular expression */
202 IMAP_SearchInit();
203
204 /* Put the preprocessor function into the function list */
205 /* _dpd.addPreproc(IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP);*/
206 _dpd.addPreprocExit(IMAPCleanExitFunction, NULL, PRIORITY_LAST, PP_IMAP);
207 _dpd.addPreprocReset(IMAPResetFunction, NULL, PRIORITY_LAST, PP_IMAP);
208 _dpd.registerPreprocStats(IMAP_PROTO_REF_STR, IMAP_PrintStats);
209 _dpd.addPreprocResetStats(IMAPResetStatsFunction, NULL, PRIORITY_LAST, PP_IMAP);
210 _dpd.addPreprocConfCheck(sc, IMAPCheckConfig);
211
212 #ifdef TARGET_BASED
213 imap_proto_id = _dpd.findProtocolReference(IMAP_PROTO_REF_STR);
214 if (imap_proto_id == SFTARGET_UNKNOWN_PROTOCOL)
215 imap_proto_id = _dpd.addProtocolReference(IMAP_PROTO_REF_STR);
216
217 // register with session to handle applications
218 _dpd.sessionAPI->register_service_handler( PP_IMAP, imap_proto_id );
219
220 DEBUG_WRAP(DebugMessage(DEBUG_IMAP,"IMAP: Target-based: Proto id for %s: %u.\n",
221 IMAP_PROTO_REF_STR, imap_proto_id););
222 #endif
223
224 #ifdef PERF_PROFILING
225 _dpd.addPreprocProfileFunc("imap", (void*)&imapPerfStats, 0, _dpd.totalPerfStats, NULL);
226 #endif
227 }
228
229 sfPolicyUserPolicySet (imap_config, policy_id);
230 pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_config);
231 if (pPolicyConfig != NULL)
232 {
233 DynamicPreprocessorFatalMessage("Can only configure IMAP preprocessor once.\n");
234 }
235
236 pPolicyConfig = (IMAPConfig *)_dpd.snortAlloc(1, sizeof(IMAPConfig), PP_IMAP,
237 PP_MEM_CATEGORY_CONFIG);
238 if (pPolicyConfig == NULL)
239 {
240 DynamicPreprocessorFatalMessage("Not enough memory to create IMAP "
241 "configuration.\n");
242 }
243
244 sfPolicyUserDataSetCurrent(imap_config, pPolicyConfig);
245
246 IMAP_InitCmds(pPolicyConfig);
247 IMAP_ParseArgs(pPolicyConfig, args);
248
249 IMAP_CheckConfig(pPolicyConfig, imap_config);
250 IMAP_PrintConfig(pPolicyConfig);
251
252 if(pPolicyConfig->disabled)
253 return;
254
255 _dpd.addPreproc(sc, IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP);
256
257 if (_dpd.streamAPI == NULL)
258 {
259 DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled "
260 "for IMAP preprocessor\n");
261 }
262
263 /* Command search - do this here because it's based on configuration */
264 pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new();
265 if (pPolicyConfig->cmd_search_mpse == NULL)
266 {
267 DynamicPreprocessorFatalMessage("Could not allocate IMAP "
268 "command search.\n");
269 }
270
271 for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++)
272 {
273 pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name;
274 pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len;
275
276 _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name,
277 tmp->name_len, tmp->search_id);
278 }
279
280 _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse);
281
282 // register ports with session and stream
283 registerPortsForDispatch( sc, pPolicyConfig );
284 registerPortsForReassembly( pPolicyConfig, SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
285 _addPortsToStreamFilter(sc, pPolicyConfig, policy_id);
286
287 #ifdef TARGET_BASED
288 _addServicesToStreamFilter(sc, policy_id);
289 #endif
290 }
291
292 /*
293 * Function: IMAPDetect(void *, void *)
294 *
295 * Purpose: Perform the preprocessor's intended function. This can be
296 * simple (statistics collection) or complex (IP defragmentation)
297 * as you like. Try not to destroy the performance of the whole
298 * system by trying to do too much....
299 *
300 * Arguments: p => pointer to the current packet data struct
301 *
302 * Returns: void function
303 *
304 */
IMAPDetect(void * pkt,void * context)305 static void IMAPDetect(void *pkt, void *context)
306 {
307 SFSnortPacket *p = (SFSnortPacket *)pkt;
308 tSfPolicyId policy_id = _dpd.getNapRuntimePolicy();
309 PROFILE_VARS;
310
311 // preconditions - what we registered for
312 assert(IsTCP(p) && p->payload && p->payload_size);
313
314 PREPROC_PROFILE_START(imapPerfStats);
315
316 DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP Start (((((((((((((((((((((((((((((((((((((((\n"););
317
318 sfPolicyUserPolicySet (imap_config, policy_id);
319
320 SnortIMAP(p);
321
322 DEBUG_WRAP(DebugMessage(DEBUG_IMAP, "IMAP End )))))))))))))))))))))))))))))))))))))))))\n\n"););
323
324 PREPROC_PROFILE_END(imapPerfStats);
325 #ifdef PERF_PROFILING
326 if (PROFILING_PREPROCS && imapDetectCalled)
327 {
328 imapPerfStats.ticks -= imapDetectPerfStats.ticks;
329 /* And Reset ticks to 0 */
330 imapDetectPerfStats.ticks = 0;
331 imapDetectCalled = 0;
332 }
333 #endif
334
335 }
336
337
338 /*
339 * Function: IMAPCleanExitFunction(int, void *)
340 *
341 * Purpose: This function gets called when Snort is exiting, if there's
342 * any cleanup that needs to be performed (e.g. closing files)
343 * it should be done here.
344 *
345 * Arguments: signal => the code of the signal that was issued to Snort
346 * data => any arguments or data structs linked to this
347 * function when it was registered, may be
348 * needed to properly exit
349 *
350 * Returns: void function
351 */
IMAPCleanExitFunction(int signal,void * data)352 static void IMAPCleanExitFunction(int signal, void *data)
353 {
354 IMAP_Free();
355 if (mempool_destroy(imap_mime_mempool) == 0)
356 {
357 free(imap_mime_mempool);
358 imap_mime_mempool = NULL;
359 }
360 if (mempool_destroy(imap_mempool) == 0)
361 {
362 free(imap_mempool);
363 imap_mempool = NULL;
364 }
365
366 }
367
368
IMAPResetFunction(int signal,void * data)369 static void IMAPResetFunction(int signal, void *data)
370 {
371 return;
372 }
373
IMAPResetStatsFunction(int signal,void * data)374 static void IMAPResetStatsFunction(int signal, void *data)
375 {
376 return;
377 }
378
registerPortsForDispatch(struct _SnortConfig * sc,IMAPConfig * policy)379 static void registerPortsForDispatch( struct _SnortConfig *sc, IMAPConfig *policy )
380 {
381 int port;
382
383 for ( port = 0; port < MAXPORTS; port++ )
384 {
385 if( isPortEnabled( policy->ports, port ) )
386 _dpd.sessionAPI->enable_preproc_for_port( sc, PP_IMAP, PROTO_BIT__TCP, port );
387 }
388 }
389
registerPortsForReassembly(IMAPConfig * policy,int direction)390 static void registerPortsForReassembly( IMAPConfig *policy, int direction )
391 {
392 uint32_t port;
393
394 for ( port = 0; port < MAXPORTS; port++ )
395 {
396 if( isPortEnabled( policy->ports, port ) )
397 _dpd.streamAPI->register_reassembly_port( NULL, port, direction );
398 }
399 }
400
_addPortsToStreamFilter(struct _SnortConfig * sc,IMAPConfig * config,tSfPolicyId policy_id)401 static void _addPortsToStreamFilter(struct _SnortConfig *sc, IMAPConfig *config, tSfPolicyId policy_id)
402 {
403 unsigned int portNum;
404
405 if (config == NULL)
406 return;
407
408 for (portNum = 0; portNum < MAXPORTS; portNum++)
409 {
410 if(config->ports[(portNum/8)] & (1<<(portNum%8)))
411 {
412 //Add port the port
413 _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)portNum,
414 PORT_MONITOR_SESSION, policy_id, 1);
415 register_imap_paf_port(sc, portNum, policy_id);
416 }
417 }
418 }
419
420 #ifdef TARGET_BASED
_addServicesToStreamFilter(struct _SnortConfig * sc,tSfPolicyId policy_id)421 static void _addServicesToStreamFilter(struct _SnortConfig *sc, tSfPolicyId policy_id)
422 {
423 _dpd.streamAPI->set_service_filter_status(sc, imap_proto_id, PORT_MONITOR_SESSION, policy_id, 1);
424 register_imap_paf_service(sc, imap_proto_id, policy_id);
425 }
426 #endif
427
CheckFilePolicyConfig(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)428 static int CheckFilePolicyConfig(
429 struct _SnortConfig *sc,
430 tSfPolicyUserContextId config,
431 tSfPolicyId policyId,
432 void* pData
433 )
434 {
435 IMAPConfig *context = (IMAPConfig *)pData;
436
437 /* Use new Snort config to get the max file depth */
438 context->decode_conf.file_depth = _dpd.fileAPI->get_max_file_depth(sc, true);
439 if (context->decode_conf.file_depth > -1)
440 context->log_config.log_filename = 1;
441 updateMaxDepth(context->decode_conf.file_depth, &context->decode_conf.max_depth);
442
443 return 0;
444 }
445
IMAPEnableDecoding(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)446 static int IMAPEnableDecoding(struct _SnortConfig *sc, tSfPolicyUserContextId config,
447 tSfPolicyId policyId, void *pData)
448 {
449 IMAPConfig *context = (IMAPConfig *)pData;
450
451 if (pData == NULL)
452 return 0;
453
454 if(context->disabled)
455 return 0;
456
457 if(_dpd.fileAPI->is_decoding_enabled(&(context->decode_conf)))
458 return 1;
459
460 return 0;
461 }
462
IMAPCheckPolicyConfig(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)463 static int IMAPCheckPolicyConfig(
464 struct _SnortConfig *sc,
465 tSfPolicyUserContextId config,
466 tSfPolicyId policyId,
467 void* pData
468 )
469 {
470 IMAPConfig *context = (IMAPConfig *)pData;
471
472 _dpd.setParserPolicy(sc, policyId);
473
474 /* In a multiple-policy setting, the IMAP preproc can be turned on in a
475 "disabled" state. In this case, we don't require Stream. */
476 if (context->disabled)
477 return 0;
478
479 if (_dpd.streamAPI == NULL)
480 {
481 _dpd.errMsg("Streaming & reassembly must be enabled for IMAP preprocessor\n");
482 return -1;
483 }
484
485 return 0;
486 }
487
IMAPLogExtraData(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)488 static int IMAPLogExtraData(struct _SnortConfig *sc, tSfPolicyUserContextId config,
489 tSfPolicyId policyId, void *pData)
490 {
491 IMAPConfig *context = (IMAPConfig *)pData;
492
493 if (pData == NULL)
494 return 0;
495
496 if(context->disabled)
497 return 0;
498
499 if(context->log_config.log_filename)
500 return 1;
501
502 return 0;
503 }
504
IMAPCheckConfig(struct _SnortConfig * sc)505 static int IMAPCheckConfig(struct _SnortConfig *sc)
506 {
507 int rval;
508
509 IMAPConfig *defaultConfig =
510 (IMAPConfig *)sfPolicyUserDataGetDefault(imap_config);
511
512 if ((rval = sfPolicyUserDataIterate (sc, imap_config, IMAPCheckPolicyConfig)))
513 return rval;
514
515 if ((rval = sfPolicyUserDataIterate (sc, imap_config, CheckFilePolicyConfig)))
516 return rval;
517
518 if (sfPolicyUserDataIterate(sc, imap_config, IMAPEnableDecoding) != 0)
519 {
520 if (defaultConfig == NULL)
521 {
522 /*error message */
523 _dpd.errMsg("IMAP: Must configure a default "
524 "configuration if you want to imap decoding.\n");
525 return -1;
526 }
527
528 imap_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(defaultConfig->decode_conf.max_mime_mem,
529 defaultConfig->decode_conf.max_depth, imap_mime_mempool, PROTOCOL_NAME);
530
531 }
532
533 if (sfPolicyUserDataIterate(sc, imap_config, IMAPLogExtraData) != 0)
534 {
535 if (defaultConfig == NULL)
536 {
537 /*error message */
538 _dpd.errMsg("IMAP: Must configure a default "
539 "configuration if you want to log extra data.\n");
540 return -1;
541 }
542 imap_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0,
543 defaultConfig->memcap, imap_mempool, PROTOCOL_NAME);
544 }
545 return 0;
546 }
547
IMAP_PrintStats(int exiting)548 static void IMAP_PrintStats(int exiting)
549 {
550 _dpd.logMsg("IMAP Preprocessor Statistics\n");
551 _dpd.logMsg(" Total sessions : " STDu64 "\n", imap_stats.sessions);
552 _dpd.logMsg(" Max concurrent sessions : " STDu64 "\n", imap_stats.max_conc_sessions);
553 if (imap_stats.sessions > 0)
554 {
555 _dpd.logMsg(" Base64 attachments decoded : " STDu64 "\n", imap_stats.mime_stats.attachments[DECODE_B64]);
556 _dpd.logMsg(" Total Base64 decoded bytes : " STDu64 "\n", imap_stats.mime_stats.decoded_bytes[DECODE_B64]);
557 _dpd.logMsg(" Quoted-Printable attachments decoded : " STDu64 "\n", imap_stats.mime_stats.attachments[DECODE_QP]);
558 _dpd.logMsg(" Total Quoted decoded bytes : " STDu64 "\n", imap_stats.mime_stats.decoded_bytes[DECODE_QP]);
559 _dpd.logMsg(" UU attachments decoded : " STDu64 "\n", imap_stats.mime_stats.attachments[DECODE_UU]);
560 _dpd.logMsg(" Total UU decoded bytes : " STDu64 "\n", imap_stats.mime_stats.decoded_bytes[DECODE_UU]);
561 _dpd.logMsg(" Non-Encoded MIME attachments extracted : " STDu64 "\n", imap_stats.mime_stats.attachments[DECODE_BITENC]);
562 _dpd.logMsg(" Total Non-Encoded MIME bytes extracted : " STDu64 "\n", imap_stats.mime_stats.decoded_bytes[DECODE_BITENC]);
563 if ( imap_stats.mime_stats.memcap_exceeded )
564 _dpd.logMsg(" Sessions not decoded due to memory unavailability : " STDu64 "\n", imap_stats.mime_stats.memcap_exceeded);
565 if ( imap_stats.log_memcap_exceeded )
566 _dpd.logMsg(" IMAP sessions fastpathed due to memcap exceeded: " STDu64 "\n", imap_stats.log_memcap_exceeded);
567 }
568
569 }
570
571 #ifdef SNORT_RELOAD
IMAPReload(struct _SnortConfig * sc,char * args,void ** new_config)572 static void IMAPReload(struct _SnortConfig *sc, char *args, void **new_config)
573 {
574 tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)*new_config;
575 IMAPToken *tmp;
576 tSfPolicyId policy_id = _dpd.getParserPolicy(sc);
577 IMAPConfig *pPolicyConfig = NULL;
578
579 if (imap_swap_config == NULL)
580 {
581 //create a context
582 imap_swap_config = sfPolicyConfigCreate();
583 if (imap_swap_config == NULL)
584 {
585 DynamicPreprocessorFatalMessage("Not enough memory to create IMAP "
586 "configuration.\n");
587 }
588 *new_config = (void *)imap_swap_config;
589 }
590
591 sfPolicyUserPolicySet (imap_swap_config, policy_id);
592 pPolicyConfig = (IMAPConfig *)sfPolicyUserDataGetCurrent(imap_swap_config);
593
594 if (pPolicyConfig != NULL)
595 DynamicPreprocessorFatalMessage("Can only configure IMAP preprocessor once.\n");
596
597 pPolicyConfig = (IMAPConfig *)_dpd.snortAlloc(1, sizeof(IMAPConfig), PP_IMAP,
598 PP_MEM_CATEGORY_CONFIG);
599 if (pPolicyConfig == NULL)
600 {
601 DynamicPreprocessorFatalMessage("Not enough memory to create IMAP "
602 "configuration.\n");
603 }
604
605 sfPolicyUserDataSetCurrent(imap_swap_config, pPolicyConfig);
606
607 IMAP_InitCmds(pPolicyConfig);
608 IMAP_ParseArgs(pPolicyConfig, args);
609
610 IMAP_CheckConfig(pPolicyConfig, imap_swap_config);
611 IMAP_PrintConfig(pPolicyConfig);
612
613 if( pPolicyConfig->disabled )
614 return;
615
616 if (_dpd.streamAPI == NULL)
617 {
618 DynamicPreprocessorFatalMessage("Streaming & reassembly must be enabled "
619 "for IMAP preprocessor\n");
620 }
621
622 /* Command search - do this here because it's based on configuration */
623 pPolicyConfig->cmd_search_mpse = _dpd.searchAPI->search_instance_new();
624 if (pPolicyConfig->cmd_search_mpse == NULL)
625 {
626 DynamicPreprocessorFatalMessage("Could not allocate IMAP "
627 "command search.\n");
628 }
629
630 for (tmp = pPolicyConfig->cmds; tmp->name != NULL; tmp++)
631 {
632 pPolicyConfig->cmd_search[tmp->search_id].name = tmp->name;
633 pPolicyConfig->cmd_search[tmp->search_id].name_len = tmp->name_len;
634
635 _dpd.searchAPI->search_instance_add(pPolicyConfig->cmd_search_mpse, tmp->name,
636 tmp->name_len, tmp->search_id);
637 }
638
639 _dpd.searchAPI->search_instance_prep(pPolicyConfig->cmd_search_mpse);
640
641 _dpd.addPreproc(sc, IMAPDetect, PRIORITY_APPLICATION, PP_IMAP, PROTO_BIT__TCP);
642
643 // register ports with session and stream
644 registerPortsForDispatch( sc, pPolicyConfig );
645 registerPortsForReassembly( pPolicyConfig, SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
646 _addPortsToStreamFilter(sc, pPolicyConfig, policy_id);
647
648 #ifdef TARGET_BASED
649 _addServicesToStreamFilter(sc, policy_id);
650 #endif
651 }
652
IMAPMempoolFreeUsedBucket(MemPool * memory_pool)653 static int IMAPMempoolFreeUsedBucket(MemPool *memory_pool)
654 {
655 MemBucket *lru_bucket = NULL;
656
657 lru_bucket = mempool_get_lru_bucket(memory_pool);
658 if(lru_bucket)
659 {
660 /* Deleting least recently used IMAP session data here to adjust to new max_memory */
661 _dpd.sessionAPI->set_application_data(lru_bucket->scbPtr, PP_IMAP, NULL, NULL);
662 return 1;
663 }
664 return 0;
665 }
666
IMAPReloadMimeMempoolAdjust(unsigned imapMaxWork)667 static unsigned IMAPReloadMimeMempoolAdjust(unsigned imapMaxWork)
668 {
669 int retVal;
670
671 /* deleting MemBucket from free list in IMAP Mime Mempool */
672 imapMaxWork = mempool_prune_freelist(imap_mime_mempool, imap_mime_mempool->max_memory, imapMaxWork);
673
674 if(!imapMaxWork)
675 return 0;
676
677 for( ; imapMaxWork && ((imap_mime_mempool->used_memory + imap_mime_mempool->free_memory) > imap_mime_mempool->max_memory); imapMaxWork--)
678 {
679 /* deleting least recently used MemBucket from Used list in IMAP Mime Mempool */
680 retVal = IMAPMempoolFreeUsedBucket(imap_mime_mempool);
681 if(!retVal)
682 break;
683 }
684
685 return imapMaxWork;
686 }
687
IMAPReloadLogMempoolAdjust(unsigned imapMaxWork)688 static unsigned IMAPReloadLogMempoolAdjust(unsigned imapMaxWork)
689 {
690 int retVal;
691
692 /* deleting MemBucket from free list in IMAP Log Mempool */
693 imapMaxWork = mempool_prune_freelist(imap_mempool, imap_mempool->max_memory, imapMaxWork);
694
695 if(!imapMaxWork)
696 return 0;
697
698 for( ; imapMaxWork && ((imap_mempool->used_memory + imap_mempool->free_memory) > imap_mempool->max_memory); imapMaxWork--)
699 {
700 /* deleting least recently used MemBucket from Used list in IMAP Log Mempool */
701 retVal = IMAPMempoolFreeUsedBucket(imap_mempool);
702 if(!retVal)
703 break;
704 }
705
706 return imapMaxWork;
707 }
708
IMAPMimeReloadAdjust(bool idle,tSfPolicyId raPolicyId,void * userData)709 static bool IMAPMimeReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
710 {
711 unsigned initialMaxWork = idle ? 512 : 5;
712 unsigned maxWork;
713
714 /* If new max_mime_mem is less than old configured max_mime_mem, need to adjust IMAP Mime Mempool.
715 * In order to adjust to new max_memory of mime mempool, delete buckets from free list.
716 * After deleting buckets from free list, still new max_memory is less than old value , delete buckets
717 * (least recently used i.e head node of used list )from used list till total memory reaches to new max_memory.
718 */
719 maxWork = IMAPReloadMimeMempoolAdjust(initialMaxWork);
720
721 if(maxWork == initialMaxWork)
722 {
723 imap_stats.max_conc_sessions = imap_stats.conc_sessions;
724 imap_stats.mime_stats.memcap_exceeded = 0;
725 return true;
726 }
727 else
728 return false;
729 }
730
IMAPLogReloadAdjust(bool idle,tSfPolicyId raPolicyId,void * userData)731 static bool IMAPLogReloadAdjust(bool idle, tSfPolicyId raPolicyId, void* userData)
732 {
733 unsigned initialMaxWork = idle ? 512 : 5;
734 unsigned maxWork;
735
736 /* If new memcap is less than old configured memcap, need to adjust IMAP Log Mempool.
737 * In order to adjust to new max_memory of log mempool, delete buckets from free list.
738 * After deleting buckets from free list, still new max_memory is less than old value , delete buckets
739 * (least recently used i.e head node of used list )from used list till total memory reaches to new max_memory.
740 */
741 maxWork = IMAPReloadLogMempoolAdjust(initialMaxWork);
742
743 if (maxWork == initialMaxWork)
744 {
745 imap_stats.max_conc_sessions = imap_stats.conc_sessions;
746 imap_stats.mime_stats.memcap_exceeded = 0;
747 return true;
748 }
749 else
750 return false;
751 }
752
IMAPReloadVerify(struct _SnortConfig * sc,void * swap_config)753 static int IMAPReloadVerify(struct _SnortConfig *sc, void *swap_config)
754 {
755 tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)swap_config;
756 IMAPConfig *config = NULL;
757 IMAPConfig *configNext = NULL;
758 tSfPolicyId policy_id = 0;
759 int rval;
760
761 if (imap_swap_config == NULL)
762 return 0;
763
764 if (imap_config != NULL)
765 config = (IMAPConfig *)sfPolicyUserDataGet(imap_config, _dpd.getDefaultPolicy());
766
767 configNext = (IMAPConfig *)sfPolicyUserDataGet(imap_swap_config, _dpd.getDefaultPolicy());
768
769 if (config == NULL)
770 return 0;
771
772 if ((rval = sfPolicyUserDataIterate( sc, imap_swap_config, IMAPCheckPolicyConfig )))
773 return rval;
774
775 if ((rval = sfPolicyUserDataIterate( sc, imap_swap_config, CheckFilePolicyConfig )))
776 return rval;
777
778 policy_id = _dpd.getParserPolicy(sc);
779
780 if (imap_mime_mempool != NULL)
781 {
782 /* If max_mime_mem changes, mime mempool need to be adjusted bcz mempool max_memory will be changed.
783 Registering here to adjust Mime memory Pool when max_mime_mem changes. */
784 if( configNext->decode_conf.max_mime_mem < config->decode_conf.max_mime_mem )
785 _dpd.reloadAdjustRegister(sc, "IMAP-MIME-MEMPOOL", policy_id, &IMAPMimeReloadAdjust, NULL, NULL);
786 }
787
788 if (imap_mempool != NULL)
789 {
790 if(configNext)
791 {
792 /* If memcap cahnges, log mempool need to be adjusted bcz mempool max_mempory will be changed.
793 Registering here to adjust Log memory Pool when memcap changes. */
794 if (configNext->memcap < config->memcap)
795 _dpd.reloadAdjustRegister(sc, "IMAP-LOG-MEMPOOL", policy_id, &IMAPLogReloadAdjust, NULL, NULL);
796 }
797
798 }
799 else if(configNext != NULL)
800 {
801 if (sfPolicyUserDataIterate(sc, imap_swap_config, IMAPEnableDecoding) != 0)
802 {
803 imap_mime_mempool = (MemPool *)_dpd.fileAPI->init_mime_mempool(configNext->decode_conf.max_mime_mem,
804 configNext->decode_conf.max_depth, imap_mime_mempool, PROTOCOL_NAME);
805 }
806
807 if (sfPolicyUserDataIterate(sc, imap_swap_config, IMAPLogExtraData) != 0)
808 {
809 imap_mempool = (MemPool *)_dpd.fileAPI->init_log_mempool(0, configNext->memcap,
810 imap_mempool, PROTOCOL_NAME);
811 }
812
813 if ( configNext->disabled )
814 return 0;
815 }
816
817 if (_dpd.streamAPI == NULL)
818 {
819 _dpd.errMsg("Streaming & reassembly must be enabled for IMAP preprocessor\n");
820 return -1;
821 }
822
823 return 0;
824 }
825
IMAPReloadSwapPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)826 static int IMAPReloadSwapPolicy(
827 tSfPolicyUserContextId config,
828 tSfPolicyId policyId,
829 void* pData
830 )
831 {
832 IMAPConfig *pPolicyConfig = (IMAPConfig *)pData;
833
834 if (pPolicyConfig->ref_count == 0)
835 {
836 sfPolicyUserDataClear (config, policyId);
837 IMAP_FreeConfig(pPolicyConfig);
838 }
839
840 return 0;
841 }
842
IMAPReloadSwap(struct _SnortConfig * sc,void * swap_config)843 static void * IMAPReloadSwap(struct _SnortConfig *sc, void *swap_config)
844 {
845 IMAPConfig *configNew = NULL, *configOld = NULL;
846 tSfPolicyUserContextId imap_swap_config = (tSfPolicyUserContextId)swap_config;
847 tSfPolicyUserContextId old_config = imap_config;
848
849 if (imap_swap_config == NULL)
850 return NULL;
851
852 imap_config = imap_swap_config;
853
854 configOld = (IMAPConfig *)sfPolicyUserDataGet(old_config, _dpd.getDefaultPolicy());
855 configNew = (IMAPConfig *)sfPolicyUserDataGet(imap_config, _dpd.getDefaultPolicy());
856
857 if(configNew)
858 {
859 if(imap_mime_mempool)
860 {
861 if((configOld->decode_conf.max_mime_mem != configNew->decode_conf.max_mime_mem) ||
862 (configOld->decode_conf.max_depth != configNew->decode_conf.max_depth) )
863 {
864 #ifdef REG_TEST
865 _dpd.fileAPI->displayMimeMempool(imap_mime_mempool,&(configOld->decode_conf), &(configNew->decode_conf));
866 #endif
867 /* Update the imap_mime_mempool with new max_memmory and object size when max_mime_mem changes. */
868 _dpd.fileAPI->update_mime_mempool(imap_mime_mempool, configNew->decode_conf.max_mime_mem, configNew->decode_conf.max_depth);
869 }
870 }
871 if(imap_mempool)
872 {
873 if(configOld->memcap != configNew->memcap)
874 {
875 #ifdef REG_TEST
876 _dpd.fileAPI->displayLogMempool(imap_mempool, configOld->memcap, configNew->memcap);
877 #endif
878 /* Update the imap_mempool with new max_memory and objest size when memcap changes. */
879 _dpd.fileAPI->update_log_mempool(imap_mempool, configNew->memcap, 0);
880 imap_stats.log_memcap_exceeded = 0;
881 }
882 }
883 #ifdef REG_TEST
884 _dpd.fileAPI->displayDecodeDepth(&(configOld->decode_conf), &(configNew->decode_conf));
885 #endif
886
887 }
888
889 sfPolicyUserDataFreeIterate (old_config, IMAPReloadSwapPolicy);
890
891 if (sfPolicyUserPolicyGetActive(old_config) == 0)
892 IMAP_FreeConfigs(old_config);
893
894 return NULL;
895 }
896
IMAPReloadSwapFree(void * data)897 static void IMAPReloadSwapFree(void *data)
898 {
899 if (data == NULL)
900 return;
901
902 IMAP_FreeConfigs((tSfPolicyUserContextId)data);
903 }
904 #endif
905