"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/s7commplus/spp_s7comm.c" (16 Oct 2020, 21447 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "spp_s7comm.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * This program is free software; you can redistribute it and/or modify
    3  * it under the terms of the GNU General Public License Version 2 as
    4  * published by the Free Software Foundation.  You may not use, modify or
    5  * distribute this program under any other version of the GNU General
    6  * Public License.
    7  *
    8  * This program is distributed in the hope that it will be useful,
    9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11  * GNU General Public License for more details.
   12  *
   13  * You should have received a copy of the GNU General Public License
   14  * along with this program; if not, write to the Free Software
   15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   16  *
   17  * Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
   18  *
   19  * Authors: Jeffrey Gu <jgu@cisco.com>, Pradeep Damodharan <prdamodh@cisco.com>
   20  *
   21  * Dynamic preprocessor for the S7commplus protocol
   22  *
   23  */
   24 
   25 #ifdef HAVE_CONFIG_H
   26 #include "config.h"
   27 #endif /* HAVE_CONFIG_H */
   28 
   29 #include <assert.h>
   30 #include <string.h>
   31 
   32 #include "sf_types.h"
   33 #include "sf_snort_packet.h"
   34 #include "sf_dynamic_preprocessor.h"
   35 #include "sf_snort_plugin_api.h"
   36 #include "snort_debug.h"
   37 
   38 #include "preprocids.h"
   39 #include "spp_s7comm.h"
   40 #include "sf_preproc_info.h"
   41 
   42 #include "profiler.h"
   43 #ifdef PERF_PROFILING
   44 PreprocStats s7commplusPerfStats;
   45 #endif
   46 
   47 #include "sf_types.h"
   48 #include "s7comm_decode.h"
   49 #include "s7comm_roptions.h"
   50 #include "s7comm_paf.h"
   51 
   52 const int MAJOR_VERSION = 1;
   53 const int MINOR_VERSION = 0;
   54 const int BUILD_VERSION = 1;
   55 const char *PREPROC_NAME = "SF_S7COMMPLUS";
   56 
   57 #define SetupS7commplus DYNAMIC_PREPROC_SETUP
   58 
   59 /* Preprocessor config objects */
   60 static tSfPolicyUserContextId s7commplus_context_id = NULL;
   61 static s7commplus_config_t *s7commplus_eval_config = NULL;
   62 
   63 /* Target-based app ID */
   64 #ifdef TARGET_BASED
   65 int16_t s7commplus_app_id = SFTARGET_UNKNOWN_PROTOCOL;
   66 #endif
   67 
   68 /* Prototypes */
   69 static void S7commplusInit(struct _SnortConfig *, char *);
   70 static inline void S7commplusOneTimeInit(struct _SnortConfig *);
   71 static inline s7commplus_config_t * S7commplusPerPolicyInit(struct _SnortConfig *, tSfPolicyUserContextId);
   72 
   73 static void ProcessS7commplus(void *, void *);
   74 
   75 #ifdef SNORT_RELOAD
   76 static void S7commplusReload(struct _SnortConfig *, char *, void **);
   77 static int S7commplusReloadVerify(struct _SnortConfig *, void *);
   78 static void * S7commplusReloadSwap(struct _SnortConfig *, void *);
   79 static void S7commplusReloadSwapFree(void *);
   80 #endif
   81 
   82 static void registerPortsForDispatch( struct _SnortConfig *sc, s7commplus_config_t *policy );
   83 static void registerPortsForReassembly( s7commplus_config_t *policy, int direction );
   84 static void _addPortsToStreamFilter(struct _SnortConfig *, s7commplus_config_t *, tSfPolicyId);
   85 #ifdef TARGET_BASED
   86 static void _addServicesToStreamFilter(struct _SnortConfig *, tSfPolicyId);
   87 #endif
   88 
   89 static void S7commplusFreeConfig(tSfPolicyUserContextId context_id);
   90 static void FreeS7commplusData(void *);
   91 static int S7commplusCheckConfig(struct _SnortConfig *);
   92 static void S7commplusCleanExit(int, void *);
   93 
   94 static void ParseS7commplusArgs(s7commplus_config_t *config, char *args);
   95 static void S7commplusPrintConfig(s7commplus_config_t *config);
   96 
   97 static int S7commplusPortCheck(s7commplus_config_t *config, SFSnortPacket *packet);
   98 static s7commplus_session_data_t * S7commplusCreateSessionData(SFSnortPacket *);
   99 
  100 /* Register init callback */
  101 void SetupS7commplus(void)
  102 {
  103 #ifndef SNORT_RELOAD
  104     _dpd.registerPreproc("s7commplus", S7commplusInit);
  105 #else
  106     _dpd.registerPreproc("s7commplus", S7commplusInit, S7commplusReload,
  107                          S7commplusReloadVerify, S7commplusReloadSwap,
  108                          S7commplusReloadSwapFree);
  109 #endif
  110 }
  111 
  112 /* Allocate memory for preprocessor config, parse the args, set up callbacks */
  113 static void S7commplusInit(struct _SnortConfig *sc, char *argp)
  114 {
  115     s7commplus_config_t *s7commplus_policy = NULL;
  116 
  117     if (s7commplus_context_id == NULL)
  118     {
  119         S7commplusOneTimeInit(sc);
  120     }
  121 
  122     s7commplus_policy = S7commplusPerPolicyInit(sc, s7commplus_context_id);
  123 
  124     ParseS7commplusArgs(s7commplus_policy, argp);
  125 
  126     /* Can't add ports until they've been parsed... */
  127     S7commplusAddPortsToPaf(sc, s7commplus_policy, _dpd.getParserPolicy(sc));
  128 #ifdef TARGET_BASED
  129     S7commplusAddServiceToPaf(sc, s7commplus_app_id, _dpd.getParserPolicy(sc));
  130 #endif
  131     // register ports with session and stream
  132     registerPortsForDispatch(sc, s7commplus_policy );
  133     registerPortsForReassembly( s7commplus_policy, SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
  134     
  135     S7commplusPrintConfig(s7commplus_policy);
  136 }
  137 
  138 static inline void S7commplusOneTimeInit(struct _SnortConfig *sc)
  139 {
  140     /* context creation & error checking */
  141     s7commplus_context_id = sfPolicyConfigCreate();
  142     if (s7commplus_context_id == NULL)
  143     {
  144         _dpd.fatalMsg("%s(%d) Failed to allocate memory for "
  145                       "S7commplus config.\n", *_dpd.config_file, *_dpd.config_line);
  146     }
  147 
  148     if (_dpd.streamAPI == NULL)
  149     {
  150         _dpd.fatalMsg("%s(%d) SetupS7commplus(): The Stream preprocessor "
  151                       "must be enabled.\n", *_dpd.config_file, *_dpd.config_line);
  152     }
  153 
  154     /* callback registration */
  155     _dpd.addPreprocConfCheck(sc, S7commplusCheckConfig);
  156     _dpd.addPreprocExit(S7commplusCleanExit, NULL, PRIORITY_LAST, PP_S7COMMPLUS);
  157 
  158 #ifdef PERF_PROFILING
  159     _dpd.addPreprocProfileFunc("s7commplus", (void *)&s7commplusPerfStats, 0, _dpd.totalPerfStats, NULL);
  160 #endif
  161 
  162     /* Set up target-based app id */
  163 #ifdef TARGET_BASED
  164     s7commplus_app_id = _dpd.findProtocolReference("cotp");
  165     if (s7commplus_app_id == SFTARGET_UNKNOWN_PROTOCOL)
  166         s7commplus_app_id = _dpd.addProtocolReference("s7commplus");
  167 
  168 // register with session to handle applications
  169     _dpd.sessionAPI->register_service_handler( PP_S7COMMPLUS, s7commplus_app_id );
  170 
  171 #endif
  172 }
  173 
  174 /* Responsible for allocating a S7commplus policy. Never returns NULL. */
  175 static inline s7commplus_config_t * S7commplusPerPolicyInit(struct _SnortConfig *sc, tSfPolicyUserContextId context_id)
  176 {
  177     tSfPolicyId policy_id = _dpd.getParserPolicy(sc);
  178     s7commplus_config_t *s7commplus_policy = NULL;
  179 
  180     /* Check for existing policy & bail if found */
  181     sfPolicyUserPolicySet(context_id, policy_id);
  182     s7commplus_policy = (s7commplus_config_t *)sfPolicyUserDataGetCurrent(context_id);
  183     if (s7commplus_policy != NULL)
  184     {
  185         _dpd.fatalMsg("%s(%d) S7commplus preprocessor can only be "
  186                       "configured once.\n", *_dpd.config_file, *_dpd.config_line);
  187     }
  188 
  189     /* Allocate new policy */
  190     s7commplus_policy = (s7commplus_config_t *)calloc(1, sizeof(s7commplus_config_t));
  191     if (!s7commplus_policy)
  192     {
  193         _dpd.fatalMsg("%s(%d) Could not allocate memory for "
  194                       "s7commplus preprocessor configuration.\n"
  195                       , *_dpd.config_file, *_dpd.config_line);
  196     }
  197 
  198     sfPolicyUserDataSetCurrent(context_id, s7commplus_policy);
  199 
  200     /* Register callbacks that are done for each policy */
  201     _dpd.addPreproc(sc, ProcessS7commplus, PRIORITY_APPLICATION, PP_S7COMMPLUS, PROTO_BIT__TCP);
  202    _addPortsToStreamFilter(sc, s7commplus_policy, policy_id);
  203 #ifdef TARGET_BASED
  204     _addServicesToStreamFilter(sc, policy_id);
  205 #endif
  206 
  207     /* Add preprocessor rule options here */
  208     _dpd.preprocOptRegister(sc, S7COMMPLUS_OPCODE_NAME, S7commplusOpcodeInit, S7commplusRuleEval, free, NULL, NULL, NULL, NULL);
  209     _dpd.preprocOptRegister(sc, S7COMMPLUS_FUNC_NAME, S7commplusFuncInit, S7commplusRuleEval, free, NULL, NULL, NULL, NULL);
  210     _dpd.preprocOptRegister(sc, S7COMMPLUS_CONTENT_NAME, S7commplusContentInit, S7commplusRuleEval, free, NULL, NULL, NULL, NULL);
  211     
  212     return s7commplus_policy;
  213 }
  214 
  215 static void ParseSinglePort(s7commplus_config_t *config, char *token)
  216 {
  217     /* single port number */
  218     char *endptr;
  219     unsigned long portnum = _dpd.SnortStrtoul(token, &endptr, 10);
  220 
  221     if ((*endptr != '\0') || (portnum >= MAX_PORTS))
  222     {
  223         _dpd.fatalMsg("%s(%d) Bad s7commplus port number: %s\n"
  224                       "Port number must be an integer between 0 and 65535.\n",
  225                       *_dpd.config_file, *_dpd.config_line, token);
  226     }
  227 
  228     /* Good port number! */
  229     config->ports[PORT_INDEX(portnum)] |= CONV_PORT(portnum);
  230 }
  231 
  232 static void ParseS7commplusArgs(s7commplus_config_t *config, char *args)
  233 {
  234     char *saveptr;
  235     char *token;
  236 
  237     /* Set default port */
  238     config->ports[PORT_INDEX(S7COMMPLUS_PORT)] |= CONV_PORT(S7COMMPLUS_PORT);
  239 
  240     /* No args? Stick to the default. */
  241     if (args == NULL)
  242         return;
  243 
  244     token = strtok_r(args, " ", &saveptr);
  245     while (token != NULL)
  246     {
  247         if (strcmp(token, "ports") == 0)
  248         {
  249             unsigned nPorts = 0;
  250 
  251             /* Un-set the default port */
  252             config->ports[PORT_INDEX(S7COMMPLUS_PORT)] = 0;
  253 
  254             /* Parse ports */
  255             token = strtok_r(NULL, " ", &saveptr);
  256 
  257             if (token == NULL)
  258             {
  259                 _dpd.fatalMsg("%s(%d) Missing argument for S7commplus preprocessor "
  260                               "'ports' option.\n", *_dpd.config_file, *_dpd.config_line);
  261             }
  262 
  263             if (isdigit(token[0]))
  264             {
  265                 ParseSinglePort(config, token);
  266                 nPorts++;
  267             }
  268 
  269             else if (*token == '{')
  270             {
  271                 /* list of ports */
  272                 token = strtok_r(NULL, " ", &saveptr);
  273                 while (token != NULL && *token != '}')
  274                 {
  275                     ParseSinglePort(config, token);
  276                     nPorts++;
  277                     token = strtok_r(NULL, " ", &saveptr);
  278                 }
  279             }
  280 
  281             else
  282             {
  283                 nPorts = 0;
  284             }
  285             if ( nPorts == 0 )
  286             {
  287                 _dpd.fatalMsg("%s(%d) Bad S7commplus 'ports' argument: '%s'\n"
  288                               "Argument to S7commplus 'ports' must be an integer, or a list "
  289                               "enclosed in { } braces.\n", *_dpd.config_file, *_dpd.config_line, token);
  290             }
  291         }
  292         else
  293         {
  294             _dpd.fatalMsg("%s(%d) Failed to parse s7commplus argument: %s\n",
  295                           *_dpd.config_file, *_dpd.config_line, token);
  296         }
  297 
  298         token = strtok_r(NULL, " ", &saveptr);
  299     }
  300 
  301 }
  302 
  303 /* Print a S7commplus config */
  304 static void S7commplusPrintConfig(s7commplus_config_t *config)
  305 {
  306     int index;
  307     int newline = 1;
  308 
  309     if (config == NULL)
  310         return;
  311 
  312     _dpd.logMsg("S7commplus config: \n");
  313     _dpd.logMsg("    Ports:\n");
  314 
  315     /* Loop through port array & print, 5 ports per line */
  316     for (index = 0; index < MAX_PORTS; index++)
  317     {
  318         if (config->ports[PORT_INDEX(index)] & CONV_PORT(index))
  319         {
  320             _dpd.logMsg("\t%d", index);
  321             if ( !((newline++) % 5) )
  322             {
  323                 _dpd.logMsg("\n");
  324             }
  325         }
  326     }
  327     _dpd.logMsg("\n");
  328 }
  329 
  330 /* Main runtime entry point */
  331 static void ProcessS7commplus(void *ipacketp, void *contextp)
  332 {
  333     SFSnortPacket *packetp = (SFSnortPacket *)ipacketp;
  334     s7commplus_session_data_t *sessp;
  335     PROFILE_VARS;
  336 
  337     // preconditions - what we registered for
  338     assert(IsTCP(packetp) && packetp->payload && packetp->payload_size);
  339 
  340     PREPROC_PROFILE_START(s7commplusPerfStats);
  341 
  342     /* Fetch me a preprocessor config to use with this VLAN/subnet/etc.! */
  343     s7commplus_eval_config = sfPolicyUserDataGetCurrent(s7commplus_context_id);
  344 
  345     /* Look for a previously-allocated session data. */
  346     sessp = _dpd.sessionAPI->get_application_data(packetp->stream_session, PP_S7COMMPLUS);
  347 
  348     if (sessp == NULL)
  349     {
  350         /* No existing session. Check those ports. */
  351         if (S7commplusPortCheck(s7commplus_eval_config, packetp) != true)
  352         {
  353             PREPROC_PROFILE_END(s7commplusPerfStats);
  354             return;
  355         }
  356     }
  357 
  358     if ( !PacketHasFullPDU(packetp) && S7commplusIsPafActive(packetp) )
  359     {
  360         /* If a packet is rebuilt, but not a full PDU, then it's garbage that
  361            got flushed at the end of a stream. */
  362         if ( packetp->flags & (FLAG_REBUILT_STREAM|FLAG_PDU_HEAD) )
  363         {
  364             _dpd.alertAdd(GENERATOR_SPP_S7COMMPLUS, S7COMMPLUS_BAD_LENGTH, 1, 0, 3,
  365                           S7COMMPLUS_BAD_LENGTH_STR, 0);
  366         }
  367 
  368         PREPROC_PROFILE_END(s7commplusPerfStats);
  369         return;
  370     }
  371 
  372     if (sessp == NULL)
  373     {
  374         /* Create session data and attach it to the Stream session */
  375         sessp = S7commplusCreateSessionData(packetp);
  376 
  377         if ( !sessp )
  378         {
  379             PREPROC_PROFILE_END(s7commplusPerfStats);
  380             return;
  381         }
  382     }
  383 
  384     /* When pipelined S7commplus PDUs appear in a single TCP segment, the
  385        detection engine caches the results of the rule options after
  386        evaluating on the first PDU. Setting this flag stops the caching. */
  387     packetp->flags |= FLAG_ALLOW_MULTIPLE_DETECT;
  388 
  389     /* Do preprocessor-specific detection stuff here */
  390     S7commplusDecode(s7commplus_eval_config, packetp);
  391 
  392     /* That's the end! */
  393     PREPROC_PROFILE_END(s7commplusPerfStats);
  394 }
  395 
  396 /* Check ports & services */
  397 static int S7commplusPortCheck(s7commplus_config_t *config, SFSnortPacket *packet)
  398 {
  399 #ifdef TARGET_BASED
  400     int16_t app_id = _dpd.sessionAPI->get_application_protocol_id(packet->stream_session);
  401 
  402     /* call to get_application_protocol_id gave an error */
  403     if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
  404         return false;
  405 
  406     /* this is identified as non-s7commplus */
  407     if (app_id && (app_id != s7commplus_app_id))
  408         return false;
  409 
  410     /* this is identified as s7commplus */
  411     if (app_id == s7commplus_app_id)
  412         return true;
  413 
  414     /* fall back to port check */
  415 #endif
  416 
  417     if (config->ports[PORT_INDEX(packet->src_port)] & CONV_PORT(packet->src_port))
  418         return true;
  419 
  420     if (config->ports[PORT_INDEX(packet->dst_port)] & CONV_PORT(packet->dst_port))
  421         return true;
  422 
  423     return false;
  424 }
  425 
  426 static s7commplus_session_data_t* S7commplusCreateSessionData(SFSnortPacket *packet)
  427 {
  428     s7commplus_session_data_t *data = NULL;
  429 
  430     /* Sanity Check */
  431     if (!packet || !packet->stream_session)
  432         return NULL;
  433 
  434     data = (s7commplus_session_data_t *)calloc(1, sizeof(s7commplus_session_data_t));
  435 
  436     if (!data)
  437         return NULL;
  438 
  439     /* Attach to Stream session */
  440     _dpd.sessionAPI->set_application_data(packet->stream_session, PP_S7COMMPLUS,
  441         data, FreeS7commplusData);
  442 
  443     /* This reference counting stuff got from old preprocs */
  444     data->policy_id = _dpd.getNapRuntimePolicy();
  445     data->context_id = s7commplus_context_id;
  446     ((s7commplus_config_t *)sfPolicyUserDataGetCurrent(s7commplus_context_id))->ref_count++;
  447 
  448     return data;
  449 }
  450 
  451 /* Reload functions */
  452 #ifdef SNORT_RELOAD
  453 /* Almost like S7commplusInit, but not quite. */
  454 static void S7commplusReload(struct _SnortConfig *sc, char *args, void **new_config)
  455 {
  456     tSfPolicyUserContextId s7commplus_swap_context_id = (tSfPolicyUserContextId)*new_config;
  457     s7commplus_config_t *s7commplus_policy = NULL;
  458 
  459     if (s7commplus_swap_context_id == NULL)
  460     {
  461         s7commplus_swap_context_id = sfPolicyConfigCreate();
  462         if (s7commplus_swap_context_id == NULL)
  463         {
  464             _dpd.fatalMsg("Failed to allocate memory "
  465                                             "for S7commplus config.\n");
  466         }
  467 
  468         if (_dpd.streamAPI == NULL)
  469         {
  470             _dpd.fatalMsg("SetupS7commplus(): The Stream preprocessor "
  471                                             "must be enabled.\n");
  472         }
  473         *new_config = (void *)s7commplus_swap_context_id;
  474     }
  475 
  476     s7commplus_policy = S7commplusPerPolicyInit(sc, s7commplus_swap_context_id);
  477 
  478     ParseS7commplusArgs(s7commplus_policy, args);
  479 
  480     /* Can't add ports until they've been parsed... */
  481     S7commplusAddPortsToPaf(sc, s7commplus_policy, _dpd.getParserPolicy(sc));
  482 
  483     S7commplusPrintConfig(s7commplus_policy);
  484 }
  485 
  486 static int S7commplusReloadVerify(struct _SnortConfig *sc, void *swap_config)
  487 {
  488     if (!_dpd.isPreprocEnabled(sc, PP_STREAM))
  489     {
  490         _dpd.errMsg("SetupS7commplus(): The Stream preprocessor must be enabled.\n");
  491         return -1;
  492     }
  493 
  494     return 0;
  495 }
  496 
  497 static int S7commplusFreeUnusedConfigPolicy(
  498     tSfPolicyUserContextId context_id,
  499     tSfPolicyId policy_id,
  500     void *data
  501     )
  502 {
  503     s7commplus_config_t *s7commplus_config = (s7commplus_config_t *)data;
  504 
  505     /* do any housekeeping before freeing s7commplus config */
  506     if (s7commplus_config->ref_count == 0)
  507     {
  508         sfPolicyUserDataClear(context_id, policy_id);
  509         free(s7commplus_config);
  510     }
  511 
  512     return 0;
  513 }
  514 
  515 static void * S7commplusReloadSwap(struct _SnortConfig *sc, void *swap_config)
  516 {
  517     tSfPolicyUserContextId s7commplus_swap_context_id = (tSfPolicyUserContextId)swap_config;
  518     tSfPolicyUserContextId old_context_id = s7commplus_context_id;
  519 
  520     if (s7commplus_swap_context_id == NULL)
  521         return NULL;
  522 
  523     s7commplus_context_id = s7commplus_swap_context_id;
  524 
  525     sfPolicyUserDataFreeIterate(old_context_id, S7commplusFreeUnusedConfigPolicy);
  526 
  527     if (sfPolicyUserPolicyGetActive(old_context_id) == 0)
  528     {
  529         /* No more outstanding configs - free the config array */
  530         return (void *)old_context_id;
  531     }
  532 
  533     return NULL;
  534 }
  535 
  536 static void S7commplusReloadSwapFree(void *data)
  537 {
  538     if (data == NULL)
  539         return;
  540 
  541     S7commplusFreeConfig( (tSfPolicyUserContextId)data );
  542 }
  543 #endif   //Reload functions ends here
  544 
  545 static void registerPortsForDispatch( struct _SnortConfig *sc, s7commplus_config_t *policy )
  546 {
  547     uint32_t port;
  548 
  549     for ( port = 0; port < MAX_PORTS; port++ )
  550     {
  551         if( isPortEnabled( policy->ports, port ) )
  552             _dpd.sessionAPI->enable_preproc_for_port( sc, PP_S7COMMPLUS, PROTO_BIT__TCP, port ); 
  553     }
  554 }
  555 
  556 static void registerPortsForReassembly( s7commplus_config_t *policy, int direction )
  557 {
  558     uint32_t port;
  559 
  560     for ( port = 0; port < MAX_PORTS; port++ )
  561     {
  562         if( isPortEnabled( policy->ports, port ) )
  563             _dpd.streamAPI->register_reassembly_port( NULL, port, direction );
  564     }
  565 }
  566 
  567 /* Stream filter functions */
  568 static void _addPortsToStreamFilter(struct _SnortConfig *sc, s7commplus_config_t *config, tSfPolicyId policy_id)
  569 {
  570     if (config == NULL)
  571         return;
  572 
  573     if (_dpd.streamAPI)
  574     {
  575         int portNum;
  576 
  577         for (portNum = 0; portNum < MAX_PORTS; portNum++)
  578         {
  579             if(config->ports[(portNum/8)] & (1<<(portNum%8)))
  580             {
  581                 //Add port the port
  582                 _dpd.streamAPI->set_port_filter_status( sc, IPPROTO_TCP, (uint16_t)portNum,
  583                                                         PORT_MONITOR_SESSION, policy_id, 1 );
  584             }
  585         }
  586     }
  587 
  588 }
  589 
  590 #ifdef TARGET_BASED
  591 static void _addServicesToStreamFilter(struct _SnortConfig *sc, tSfPolicyId policy_id)
  592 {
  593     _dpd.streamAPI->set_service_filter_status(sc, s7commplus_app_id, PORT_MONITOR_SESSION, policy_id, 1);
  594 }
  595 #endif
  596 
  597 static int S7commplusFreeConfigPolicy(
  598     tSfPolicyUserContextId context_id,
  599     tSfPolicyId policy_id,
  600     void *data
  601     )
  602 {
  603     s7commplus_config_t *s7commplus_config = (s7commplus_config_t *)data;
  604 
  605     /* do any housekeeping before freeing s7commplus_config */
  606 
  607     sfPolicyUserDataClear(context_id, policy_id);
  608     free(s7commplus_config);
  609     return 0;
  610 }
  611 
  612 static void S7commplusFreeConfig(tSfPolicyUserContextId context_id)
  613 {
  614     if (context_id == NULL)
  615         return;
  616 
  617     sfPolicyUserDataFreeIterate(context_id, S7commplusFreeConfigPolicy);
  618     sfPolicyConfigDelete(context_id);
  619 }
  620 
  621 static int S7commplusCheckPolicyConfig(
  622     struct _SnortConfig *sc,
  623     tSfPolicyUserContextId context_id,
  624     tSfPolicyId policy_id,
  625     void *data
  626     )
  627 {
  628     _dpd.setParserPolicy(sc, policy_id);
  629 
  630     if (!_dpd.isPreprocEnabled(sc, PP_STREAM))
  631     {
  632         _dpd.errMsg("%s(%d) S7commplusCheckPolicyConfig(): The Stream preprocessor "
  633                       "must be enabled.\n", *_dpd.config_file, *_dpd.config_line);
  634         return -1;
  635     }
  636     return 0;
  637 }
  638 
  639 static int S7commplusCheckConfig(struct _SnortConfig *sc)
  640 {
  641     int rval;
  642 
  643     if ((rval = sfPolicyUserDataIterate(sc, s7commplus_context_id, S7commplusCheckPolicyConfig)))
  644         return rval;
  645 
  646     return 0;
  647 }
  648 
  649 static void S7commplusCleanExit(int signal, void *data)
  650 {
  651     if (s7commplus_context_id != NULL)
  652     {
  653         S7commplusFreeConfig(s7commplus_context_id);
  654         s7commplus_context_id = NULL;
  655     }
  656 }
  657 
  658 static void FreeS7commplusData(void *data)
  659 {
  660     s7commplus_session_data_t *session = (s7commplus_session_data_t *)data;
  661     s7commplus_config_t *config = NULL;
  662 
  663     if (session == NULL)
  664         return;
  665 
  666     if (session->context_id != NULL)
  667     {
  668         config = (s7commplus_config_t *)sfPolicyUserDataGet(session->context_id, session->policy_id);
  669     }
  670 
  671     if (config != NULL)
  672     {
  673         config->ref_count--;
  674         if ((config->ref_count == 0) &&
  675             (session->context_id != s7commplus_context_id))
  676         {
  677             sfPolicyUserDataClear(session->context_id, session->policy_id);
  678             free(config);
  679 
  680             if (sfPolicyUserPolicyGetActive(session->context_id) == 0)
  681             {
  682                 /* No more outstanding configs - free the config array */
  683                 S7commplusFreeConfig(session->context_id);
  684             }
  685         }
  686     }
  687     free(session);
  688 }