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