1 /****************************************************************************
2 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 * Copyright (C) 2008-2013 Sourcefire, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License Version 2 as
7 * published by the Free Software Foundation. You may not use, modify or
8 * distribute this program under any other version of the GNU General
9 * Public License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 ****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "stdlib.h"
27 #include "stdio.h"
28 #include "string.h"
29 #include "sfPolicy.h"
30 #include "snort_debug.h"
31 #include "sfrt.h"
32
33 tSfPolicyId napRuntimePolicyId = 0;
34 tSfPolicyId ipsRuntimePolicyId = 0;
35
IsBound(tSfPolicyId id)36 static inline int IsBound (
37 tSfPolicyId id
38 )
39 {
40 return ( id != SF_POLICY_UNBOUND );
41 }
42
NotBound(tSfPolicyId id)43 static inline int NotBound (
44 tSfPolicyId id
45 )
46 {
47 return !IsBound(id);
48 }
49
50 static void netBindFree(
51 void *policy,
52 void *config
53 );
54
sfPolicyInit(void)55 tSfPolicyConfig * sfPolicyInit(void)
56 {
57 int i;
58 tSfPolicyConfig *new = (tSfPolicyConfig *)calloc(1, sizeof(tSfPolicyConfig));
59
60 if (new == NULL)
61 return NULL;
62
63 //initialize vlan bindings
64 for (i = 0; i < SF_VLAN_BINDING_MAX; i++)
65 {
66 new->vlanBindings[i] = SF_POLICY_UNBOUND;
67 }
68
69 for (i = 0; i < SF_POLICY_ID_BINDING_MAX; i++)
70 {
71 new->policyIdBindings[i] = SF_POLICY_UNBOUND;
72 }
73
74 //initialize net bindings
75 new->netBindTable = sfrt_new(DIR_16x7_4x4, IPv6, SF_NETWORK_BINDING_MAX, 20);
76
77 return new;
78 }
79
sfPolicyFini(tSfPolicyConfig * config)80 void sfPolicyFini(tSfPolicyConfig *config)
81 {
82 int i;
83
84 if (config == NULL)
85 return;
86
87 for (i = 0; i < SF_VLAN_BINDING_MAX; i++)
88 {
89 sfVlanDeleteBinding(config, i);
90 }
91
92 for (i = 0; i < SF_POLICY_ID_BINDING_MAX; i++)
93 {
94 sfPolicyIdDeleteBinding(config, i);
95 }
96
97 sfrt_cleanup2(config->netBindTable, netBindFree, config);
98 sfrt_free(config->netBindTable);
99
100 //policyConfig are deleted when all bindings to it are deleted.
101
102 /* free default policy */
103
104 if (config->ppPolicies != NULL)
105 {
106 sfPolicyDelete(config, config->defaultPolicyId);
107 free(config->ppPolicies);
108 }
109
110 free(config);
111 }
112
netBindFree(void * policyId,void * config)113 static void netBindFree(
114 void *policyId,
115 void *config
116 )
117 {
118 if (policyId && config)
119 {
120 sfPolicyDelete((tSfPolicyConfig *)config, *((tSfPolicyId *)policyId));
121 free(policyId);
122 }
123 }
124
125 /**Tracks filename to vlan group id */
sfPolicyAdd(tSfPolicyConfig * config,char * fileName)126 int sfPolicyAdd(tSfPolicyConfig *config, char *fileName)
127 {
128 tSfPolicy *pObject = NULL;
129 int emptyIndex = -1;
130 tSfPolicyId i;
131 tSfPolicy **ppTmp;
132
133 if (config == NULL)
134 return SF_POLICY_UNBOUND;
135
136 for (i = 0; i < config->numAllocatedPolicies; i++)
137 {
138 if (config->ppPolicies[i])
139 {
140 if (!strcmp(config->ppPolicies[i]->filename, fileName))
141 {
142 config->ppPolicies[i]->refCount++;
143 return i;
144 }
145 }
146 else if (emptyIndex == -1)
147 {
148 emptyIndex = i;
149 }
150 }
151
152 if (emptyIndex == -1)
153 {
154 //no empty slot available. Allocate more space for policies
155 ppTmp = (tSfPolicy **)calloc(config->numAllocatedPolicies + POLICY_ALLOCATION_CHUNK,
156 sizeof(tSfPolicy *));
157 if (!ppTmp)
158 return SF_POLICY_UNBOUND;
159
160 if (config->numAllocatedPolicies)
161 {
162 memcpy(ppTmp, config->ppPolicies,
163 sizeof(tSfPolicyConfig *) * config->numAllocatedPolicies);
164 free(config->ppPolicies);
165 }
166
167 config->ppPolicies = ppTmp;
168 emptyIndex = config->numAllocatedPolicies;
169 config->numAllocatedPolicies += POLICY_ALLOCATION_CHUNK;
170 }
171
172 //allocate and initialize
173 pObject = (tSfPolicy *)calloc(1, sizeof(tSfPolicy));
174 if (!pObject)
175 return SF_POLICY_UNBOUND;
176
177 pObject->refCount++;
178 pObject->filename = strdup(fileName);
179 if (!pObject->filename)
180 {
181 free(pObject);
182 return SF_POLICY_UNBOUND;
183 }
184
185 config->ppPolicies[emptyIndex] = pObject;
186 config->numActivePolicies++;
187
188 //successfully added.
189 return emptyIndex;
190 }
191
sfPolicyDelete(tSfPolicyConfig * config,tSfPolicyId policyId)192 void sfPolicyDelete(tSfPolicyConfig *config, tSfPolicyId policyId)
193 {
194 tSfPolicy *pObject = NULL;
195
196 if ((config == NULL) || (config->ppPolicies == NULL) ||
197 (policyId >= config->numAllocatedPolicies))
198 {
199 return;
200 }
201
202 pObject = config->ppPolicies[policyId];
203
204 if (pObject)
205 {
206 pObject->refCount--;
207 if (pObject->refCount == 0)
208 {
209 if (pObject->filename)
210 free(pObject->filename);
211 free(pObject);
212 config->ppPolicies[policyId] = NULL;
213 config->numActivePolicies--;
214 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
215 "sfPolicyDelete: freed policyConfig policyId %d\n", policyId););
216 }
217 }
218 }
219
sfPolicyGet(tSfPolicyConfig * config,tSfPolicyId policyId)220 char * sfPolicyGet(tSfPolicyConfig *config, tSfPolicyId policyId)
221 {
222 tSfPolicy *pObject = NULL;
223
224 if ((config == NULL) || (config->ppPolicies == NULL) ||
225 (policyId >= config->numAllocatedPolicies))
226 {
227 return NULL;
228 }
229
230 pObject = config->ppPolicies[policyId];
231 if (pObject)
232 return pObject->filename;
233
234 return NULL;
235 }
236
237
238
239 /**Creates policyId if needed and creates a binding between vlan and policyId.
240 * Tracks vlanId to vlan group id mapping
241 */
242 //TBD replace calloc with SnortAlloc()
sfVlanAddBinding(tSfPolicyConfig * config,int vlanId,char * fileName)243 int sfVlanAddBinding(tSfPolicyConfig *config, int vlanId, char *fileName)
244 {
245 tSfPolicyId policyId;
246
247 if (config == NULL || vlanId >= SF_VLAN_BINDING_MAX)
248 return -1;
249
250 //create a policyId
251 policyId = sfPolicyAdd(config, fileName);
252
253 if ( NotBound(policyId) )
254 {
255 return -1;
256 }
257
258 config->vlanBindings[vlanId] = policyId;
259
260 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
261 "Added vlandId %d, file %s, policyId: %d\n", vlanId, fileName, policyId););
262 return 0;
263 }
264
sfVlanGetBinding(tSfPolicyConfig * config,int vlanId)265 tSfPolicyId sfVlanGetBinding(tSfPolicyConfig *config, int vlanId)
266 {
267 tSfPolicyId policyId;
268
269 if(vlanId >= SF_VLAN_BINDING_MAX){
270 //invalid policyid will never be bound. return default
271 return config->defaultPolicyId;
272 }
273
274 policyId = config->vlanBindings[vlanId];
275
276 if ( NotBound(policyId) )
277 {
278 //return default policyId for uninitialized binding
279 return config->defaultPolicyId;
280 }
281
282 return policyId;
283 }
284
sfVlanDeleteBinding(tSfPolicyConfig * config,int vlanId)285 void sfVlanDeleteBinding(tSfPolicyConfig *config, int vlanId)
286 {
287 tSfPolicyId policyId;
288 if(vlanId >= SF_VLAN_BINDING_MAX)
289 return; //invalid, can't delete
290
291 if ((config == NULL) || (vlanId < 0))
292 return;
293
294 policyId = config->vlanBindings[vlanId];
295
296 if ( IsBound(policyId) )
297 {
298 sfPolicyDelete(config, policyId);
299 config->vlanBindings[vlanId] = SF_POLICY_UNBOUND;
300 }
301 }
302
sfPolicyIdAddBinding(tSfPolicyConfig * config,int parsedPolicyId,char * fileName)303 int sfPolicyIdAddBinding(tSfPolicyConfig *config, int parsedPolicyId, char *fileName)
304 {
305 tSfPolicyId policyId;
306
307 if (config == NULL || parsedPolicyId >= SF_POLICY_ID_BINDING_MAX)
308 return -1;
309
310 //create a policyId
311 policyId = sfPolicyAdd(config, fileName);
312
313 if ( NotBound(policyId) )
314 {
315 return -1;
316 }
317
318 config->policyIdBindings[parsedPolicyId] = policyId;
319
320 DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
321 "Added parsedPolicyId %d, file %s, policyId: %d\n", parsedPolicyId, fileName, policyId););
322 return 0;
323 }
324
sfPolicyIdGetBinding(tSfPolicyConfig * config,int parsedPolicyId)325 tSfPolicyId sfPolicyIdGetBinding(tSfPolicyConfig *config, int parsedPolicyId)
326 {
327 tSfPolicyId policyId;
328
329 if(parsedPolicyId >= SF_POLICY_ID_BINDING_MAX){
330 //invalid policyid will never be bound. return default
331 return config->defaultPolicyId;
332 }
333 policyId = config->policyIdBindings[parsedPolicyId];
334
335 if ( NotBound(policyId) )
336 {
337 //return default policyId for uninitialized binding
338 return config->defaultPolicyId;
339 }
340
341 return policyId;
342 }
343
sfPolicyIdDeleteBinding(tSfPolicyConfig * config,int parsedPolicyId)344 void sfPolicyIdDeleteBinding(tSfPolicyConfig *config, int parsedPolicyId)
345 {
346 tSfPolicyId policyId;
347
348 if(parsedPolicyId >= SF_POLICY_ID_BINDING_MAX)
349 return; //invalid, can't delete
350
351 if ((config == NULL) || (parsedPolicyId < 0))
352 return;
353
354 policyId = config->policyIdBindings[parsedPolicyId];
355
356 if ( IsBound(policyId) )
357 {
358 sfPolicyDelete(config, policyId);
359 config->policyIdBindings[parsedPolicyId] = SF_POLICY_UNBOUND;
360 }
361 }
362
363 /**Get applicable policy given <vlan, srcIp, dstIp> of a packet. Vlan can be negative
364 * number if vlan header is not present.
365 *
366 * Search policy bound to vlan if vlan is not negative. If matched polciy is default one,
367 * then search using destination IP address. If matched policy is default then search using
368 * source IP address.
369 *
370 * @param vlanId - vlan id from a packet. Should be unbound if vlan tag is not present.
371 * @param srcIP - Source IP address
372 * @param dstIP - Destination IP address
373 *
374 * @returns policyId
375 */
sfGetApplicablePolicyId(tSfPolicyConfig * config,int vlanId,sfaddr_t * srcIp,sfaddr_t * dstIp)376 tSfPolicyId sfGetApplicablePolicyId(
377 tSfPolicyConfig *config,
378 int vlanId,
379 sfaddr_t* srcIp,
380 sfaddr_t* dstIp
381 )
382 {
383 tSfPolicyId dst_id;
384
385 if (config == NULL)
386 return SF_POLICY_UNBOUND;
387
388 if (vlanId > 0)
389 {
390 tSfPolicyId vlan_id = sfVlanGetBinding(config, vlanId);
391 if (vlan_id > 0)
392 return vlan_id;
393 }
394
395 dst_id = sfNetworkGetBinding(config, dstIp);
396 return (dst_id > 0 ? dst_id : sfNetworkGetBinding(config, srcIp));
397 }
398
399 /**Add network binding to a policy
400 * @param Ip - IP address or CIDR block to policy identified by file.
401 * @param fileName - name of configuration file
402 *
403 * @returns 0 if successful, -1 otherwise.
404 */
sfNetworkAddBinding(tSfPolicyConfig * config,sfcidr_t * Ip,char * fileName)405 int sfNetworkAddBinding(
406 tSfPolicyConfig *config,
407 sfcidr_t* Ip,
408 char *fileName
409 )
410 {
411 tSfPolicyId *policyId;
412 int iRet;
413
414 if ((config == NULL) || (Ip == NULL) || (fileName == NULL))
415 return -1;
416
417 if ((policyId = calloc(sizeof(tSfPolicyId), 1)) == NULL)
418 {
419 return -1;
420 }
421
422 //create a policyId
423 *policyId = sfPolicyAdd(config, fileName);
424 if ( NotBound(*policyId) )
425 {
426 free(policyId);
427 return -1;
428 }
429
430 iRet = sfrt_insert(Ip, (unsigned char)Ip->bits,
431 (void *)policyId, RT_FAVOR_SPECIFIC, config->netBindTable);
432
433 //DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Added vlandId %d, file %s, policyId: %d\n", vlanId, fileName, policyId););
434 if (iRet)
435 {
436 free(policyId);
437 return -1;
438 }
439
440 return 0;
441 }
442
sfNetworkGetBinding(tSfPolicyConfig * config,sfaddr_t * ip)443 unsigned int sfNetworkGetBinding(
444 tSfPolicyConfig *config,
445 sfaddr_t* ip
446 )
447 {
448 tSfPolicyId *policyId = NULL;
449
450 if ((void *)ip == NULL)
451 return config->defaultPolicyId;
452
453 policyId = (tSfPolicyId *)sfrt_lookup(ip, config->netBindTable);
454
455 if (!policyId)
456 {
457 return config->defaultPolicyId;
458 }
459
460 return *policyId;
461 }
462
sfNetworkDeleteBinding(tSfPolicyConfig * config,sfaddr_t * ip)463 void sfNetworkDeleteBinding(
464 tSfPolicyConfig *config,
465 sfaddr_t* ip
466 )
467 {
468 tSfPolicyId *policyId;
469
470 if ((void *)ip == NULL)
471 return;
472
473 policyId = (tSfPolicyId *)sfrt_lookup(ip, config->netBindTable);
474
475 if (!policyId)
476 return;
477
478 //TBD - delete function is not provided in sfrt.c
479 sfPolicyDelete(config, *policyId);
480 }
481
482 //Move to sfDynArray.c/h
483 /**Dynamic array bound checks. If index is greater than maxElement then realloc like operation
484 * is performed.
485 * @param dynArray - dynamic array
486 * @param index - 0 based. Index of element that will be accessed by application either as rvalue or lvalue.
487 * @maxElements - Number of elements already allocated in dynArray. 0 value means no elements are allocated
488 * and therefore dynArray[0] will cause memory allocation.
489 */
sfDynArrayCheckBounds(void ** dynArray,unsigned int index,unsigned int * maxElements)490 int sfDynArrayCheckBounds (
491 void ** dynArray,
492 unsigned int index,
493 unsigned int *maxElements
494 )
495 {
496 void *ppTmp = NULL;
497
498 if (index >= *maxElements)
499 {
500 //expand the array
501 ppTmp = calloc(index+POLICY_ALLOCATION_CHUNK, sizeof(void *));
502 if (!(ppTmp))
503 {
504 return -1;
505 }
506
507 if (*maxElements)
508 {
509 memcpy(ppTmp, *dynArray, sizeof(void*)*(*maxElements));
510 free(*dynArray);
511 }
512
513 *dynArray = ppTmp;
514 *maxElements = index + POLICY_ALLOCATION_CHUNK;
515 }
516
517 return 0;
518 }
519