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