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 */
SetupS7commplus(void)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 */
S7commplusInit(struct _SnortConfig * sc,char * argp)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
S7commplusOneTimeInit(struct _SnortConfig * sc)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. */
S7commplusPerPolicyInit(struct _SnortConfig * sc,tSfPolicyUserContextId context_id)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
ParseSinglePort(s7commplus_config_t * config,char * token)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
ParseS7commplusArgs(s7commplus_config_t * config,char * args)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 */
S7commplusPrintConfig(s7commplus_config_t * 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 */
ProcessS7commplus(void * ipacketp,void * contextp)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 */
S7commplusPortCheck(s7commplus_config_t * config,SFSnortPacket * packet)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
S7commplusCreateSessionData(SFSnortPacket * packet)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. */
S7commplusReload(struct _SnortConfig * sc,char * args,void ** new_config)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
S7commplusReloadVerify(struct _SnortConfig * sc,void * swap_config)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
S7commplusFreeUnusedConfigPolicy(tSfPolicyUserContextId context_id,tSfPolicyId policy_id,void * data)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
S7commplusReloadSwap(struct _SnortConfig * sc,void * swap_config)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
S7commplusReloadSwapFree(void * data)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
registerPortsForDispatch(struct _SnortConfig * sc,s7commplus_config_t * policy)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
registerPortsForReassembly(s7commplus_config_t * policy,int direction)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 */
_addPortsToStreamFilter(struct _SnortConfig * sc,s7commplus_config_t * config,tSfPolicyId policy_id)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
_addServicesToStreamFilter(struct _SnortConfig * sc,tSfPolicyId policy_id)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
S7commplusFreeConfigPolicy(tSfPolicyUserContextId context_id,tSfPolicyId policy_id,void * data)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
S7commplusFreeConfig(tSfPolicyUserContextId context_id)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
S7commplusCheckPolicyConfig(struct _SnortConfig * sc,tSfPolicyUserContextId context_id,tSfPolicyId policy_id,void * data)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
S7commplusCheckConfig(struct _SnortConfig * sc)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
S7commplusCleanExit(int signal,void * data)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
FreeS7commplusData(void * data)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 }
689