1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2002-2013 Sourcefire, Inc.
4 ** Author(s):   Andrew R. Baker <andrewb@sourcefire.com>
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 #include <string.h>
23 #include <ctype.h>
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "signature.h"
29 #include "util.h"
30 #include "rules.h"
31 #include "treenodes.h"
32 #include "mstring.h"
33 #include "sfutil/sfghash.h"
34 #include "snort.h"
35 #include "parser.h"
36 
37 #ifdef TARGET_BASED
38 #include "target-based/sftarget_protocol_reference.h"
39 #endif
40 #include "parser.h"
41 #include "sfPolicy.h"
42 
43 /* for eval and free functions */
44 #include "detection-plugins/sp_pattern_match.h"
45 
46 static OptTreeNode *soidOTN = NULL;
47 
48 /********************* Reference Implementation *******************************/
49 
AddReference(SnortConfig * sc,ReferenceNode ** head,char * system,char * id)50 ReferenceNode * AddReference(SnortConfig *sc, ReferenceNode **head, char *system, char *id)
51 {
52     ReferenceNode *node;
53 
54     if ((system == NULL) || (id == NULL) ||
55         (sc == NULL) || (head == NULL))
56     {
57         return NULL;
58     }
59 
60     /* create the new node */
61     node = (ReferenceNode *)SnortAlloc(sizeof(ReferenceNode));
62 
63     /* lookup the reference system */
64     node->system = ReferenceSystemLookup(sc->references, system);
65     if (node->system == NULL)
66         node->system = ReferenceSystemAdd(&sc->references, system, NULL);
67 
68     node->id = SnortStrdup(id);
69 
70     /* Add the node to the front of the list */
71     node->next = *head;
72     *head = node;
73 
74     return node;
75 }
76 
77 /* print a reference node */
FPrintReference(FILE * fp,ReferenceNode * ref_node)78 void FPrintReference(FILE *fp, ReferenceNode *ref_node)
79 {
80     if ((fp == NULL) || (ref_node == NULL))
81         return;
82 
83     if (ref_node->system != NULL)
84     {
85         if(ref_node->system->url)
86         {
87             fprintf(fp, "[Xref => %s%s]", ref_node->system->url,
88                     ref_node->id);
89         }
90         else
91         {
92             fprintf(fp, "[Xref => %s %s]", ref_node->system->name,
93                     ref_node->id);
94         }
95     }
96     else
97     {
98         fprintf(fp, "[Xref => %s]", ref_node->id);
99     }
100 }
101 
102 /********************* End of Reference Implementation ************************/
103 
104 /********************** Reference System Implementation ***********************/
105 
ReferenceSystemAdd(ReferenceSystemNode ** head,char * name,char * url)106 ReferenceSystemNode * ReferenceSystemAdd(ReferenceSystemNode **head, char *name, char *url)
107 {
108     ReferenceSystemNode *node;
109 
110     if (name == NULL)
111     {
112         ErrorMessage("NULL reference system name\n");
113         return NULL;
114     }
115 
116     if (head == NULL)
117         return NULL;
118 
119     /* create the new node */
120     node = (ReferenceSystemNode *)SnortAlloc(sizeof(ReferenceSystemNode));
121 
122     node->name = SnortStrdup(name);
123     if (url != NULL)
124         node->url = SnortStrdup(url);
125 
126     /* Add to the front of the list */
127     node->next = *head;
128     *head = node;
129 
130     return node;
131 }
132 
ReferenceSystemLookup(ReferenceSystemNode * head,char * name)133 ReferenceSystemNode * ReferenceSystemLookup(ReferenceSystemNode *head, char *name)
134 {
135     if (name == NULL)
136         return NULL;
137 
138     while (head != NULL)
139     {
140         if (strcasecmp(name, head->name) == 0)
141             break;
142 
143         head = head->next;
144     }
145 
146     return head;
147 }
148 
149 
150 /****************** End of Reference System Implementation ********************/
151 
152 /************************ Class/Priority Implementation ***********************/
153 
154 /* NOTE:  This lookup can only be done during parse time */
ClassTypeLookupByType(SnortConfig * sc,char * type)155 ClassType * ClassTypeLookupByType(SnortConfig *sc, char *type)
156 {
157     ClassType *node;
158 
159     if (sc == NULL)
160         FatalError("%s(%d) Snort config is NULL.\n", __FILE__, __LINE__);
161 
162     if (type == NULL)
163         return NULL;
164 
165     node = sc->classifications;
166 
167     while (node != NULL)
168     {
169         if (strcasecmp(type, node->type) == 0)
170             break;
171 
172         node = node->next;
173     }
174 
175     return node;
176 }
177 
178 /* NOTE:  This lookup can only be done during parse time */
ClassTypeLookupById(SnortConfig * sc,int id)179 ClassType * ClassTypeLookupById(SnortConfig *sc, int id)
180 {
181     ClassType *node;
182 
183     if (sc == NULL)
184         FatalError("%s(%d) Snort config is NULL.\n", __FILE__, __LINE__);
185 
186     node = sc->classifications;
187 
188     while (node != NULL)
189     {
190         if (id == node->id)
191             break;
192 
193         node = node->next;
194     }
195 
196     return node;
197 }
198 
SoRuleOtnLookup(SFGHASH * so_rule_otn_map,uint32_t gid,uint32_t sid)199 OptTreeNode * SoRuleOtnLookup(SFGHASH *so_rule_otn_map, uint32_t gid, uint32_t sid)
200 {
201     OptTreeNode *otn = NULL;
202     OtnKey key;
203 
204     if (so_rule_otn_map == NULL)
205         return NULL;
206 
207     key.gid = gid;
208     key.sid = sid;
209 
210     soidOTN = otn = (OptTreeNode *)sfghash_find(so_rule_otn_map, &key);
211 
212     return otn;
213 }
214 
SoRuleOtnLookupNext(uint32_t gid,uint32_t sid)215 OptTreeNode * SoRuleOtnLookupNext(uint32_t gid, uint32_t sid)
216 {
217     OptTreeNode * otn = NULL;
218 
219     if (soidOTN)
220     {
221         otn = soidOTN->nextSoid;
222         soidOTN = soidOTN->nextSoid;
223     }
224 
225     return otn;
226 }
227 
SoRuleOtnLookupNew(void)228 SFGHASH * SoRuleOtnLookupNew(void)
229 {
230     return sfghash_new(10000, sizeof(OtnKey), 0, NULL);
231 }
232 
SoRuleOtnLookupAdd(SFGHASH * so_rule_otn_map,OptTreeNode * otn)233 void SoRuleOtnLookupAdd(SFGHASH *so_rule_otn_map, OptTreeNode *otn)
234 {
235     if ((so_rule_otn_map == NULL) || (otn == NULL))
236         return;
237 
238     if (otn->sigInfo.otnKey.gid == 0)
239     {
240          otn->sigInfo.otnKey.gid = otn->sigInfo.generator;
241          otn->sigInfo.otnKey.sid = otn->sigInfo.id;
242     }
243 
244     if (sfghash_add(so_rule_otn_map, &(otn->sigInfo.otnKey), otn) == SFGHASH_INTABLE)
245     {
246          OptTreeNode *otn_original = so_rule_otn_map->cnode->data;
247 
248          if (!otn_original)
249          {
250              /* */
251              FatalError("Missing Duplicate\n");
252          }
253          while (otn_original->nextSoid)
254          {
255              otn_original = otn_original->nextSoid;
256          }
257 
258          otn_original->nextSoid = otn;
259     }
260 }
261 
SoRuleOtnLookupFree(SFGHASH * so_rule_otn_map)262 void SoRuleOtnLookupFree(SFGHASH *so_rule_otn_map)
263 {
264     if (so_rule_otn_map == NULL)
265         return;
266 
267     sfghash_delete(so_rule_otn_map);
268 }
269 
OtnRemove(SFGHASH * otn_map,SFGHASH * so_rule_otn_map,OptTreeNode * otn)270 void OtnRemove(SFGHASH *otn_map, SFGHASH *so_rule_otn_map, OptTreeNode *otn)
271 {
272     OtnKey key;
273 
274     if (otn == NULL)
275         return;
276 
277     key.gid = otn->sigInfo.generator;
278     key.sid = otn->sigInfo.id;
279 
280     if (so_rule_otn_map != NULL)
281         sfghash_remove(so_rule_otn_map, &(otn->sigInfo.otnKey));
282 
283     if (otn_map != NULL)
284         sfghash_remove(otn_map, &key);
285 }
286 
OtnDeleteData(void * data)287 void OtnDeleteData(void *data)
288 {
289     OptTreeNode *otn = (OptTreeNode *)data;
290     OptFpList *opt_func;
291 
292     if (otn == NULL)
293         return;
294 
295     opt_func = otn->opt_func;
296     while (opt_func != NULL)
297     {
298         /* For each of the pattern matcher options in this rule,
299          * delete the data associated with it.  This is the only
300          * rule option type (as of now) that this is required for since
301          * patterns are not added to the hash table (via
302          * add_detection_option()) until FinalizeContentUniqueness() is
303          * called -- after the duplicate OTN checks.
304          *
305          * All other rule option types are added to the hash table
306          * at parse time, thus the data associated with that rule
307          * option is cleaned from the hash table when the table itself
308          * is cleaned up.
309          */
310         OptFpList *tmp = opt_func;
311 
312         opt_func = opt_func->next;
313 
314         if ((tmp->OptTestFunc == CheckANDPatternMatch) ||
315             (tmp->OptTestFunc == CheckUriPatternMatch))
316         {
317             PatternMatchFree(tmp->context);
318         }
319     }
320 }
321 
OtnFree(void * data)322 void OtnFree(void *data)
323 {
324     OptTreeNode *otn = (OptTreeNode *)data;
325     OptFpList *opt_func;
326     RspFpList *rsp_func;
327     ReferenceNode *ref_node;
328 #ifdef TARGET_BASED
329     unsigned int svc_idx;
330 #endif
331 
332     if (otn == NULL)
333         return;
334 
335     /* If the opt_func list was copied from another OTN, don't free it here */
336     if (!otn->sigInfo.dup_opt_func)
337     {
338         opt_func = otn->opt_func;
339         while (opt_func != NULL)
340         {
341             OptFpList *tmp = opt_func;
342             opt_func = opt_func->next;
343             free(tmp);
344         }
345     }
346 
347     rsp_func = otn->rsp_func;
348     while (rsp_func)
349     {
350         RspFpList *tmp = rsp_func;
351         rsp_func = rsp_func->next;
352 
353         // we don't free params here because they should have been
354         // passed to add_detection_option() which will ensure the
355         // unique ones are freed once.
356         free(tmp);
357     }
358 
359     if (otn->sigInfo.message != NULL)
360     {
361         if (!otn->generated)
362             free((void*)otn->sigInfo.message);
363     }
364 #ifdef TARGET_BASED
365     for (svc_idx = 0; svc_idx < otn->sigInfo.num_services; svc_idx++)
366     {
367         if (otn->sigInfo.services[svc_idx].service)
368             free(otn->sigInfo.services[svc_idx].service);
369     }
370     if (otn->sigInfo.services)
371         free(otn->sigInfo.services);
372 #endif
373 
374     ref_node = otn->sigInfo.refs;
375     while (ref_node != NULL)
376     {
377         ReferenceNode *tmp = ref_node;
378 
379         ref_node = ref_node->next;
380         free(tmp->id);
381         free(tmp);
382     }
383 
384     if (otn->tag != NULL)
385         free(otn->tag);
386 
387     /* RTN was generated on the fly.  Don't necessarily know which policy
388      * at this point so go through all RTNs and delete them */
389     if (otn->generated)
390     {
391         int i;
392 
393         for (i = 0; i < otn->proto_node_num; i++)
394         {
395             RuleTreeNode *rtn = deleteRtnFromOtn(NULL, otn, i);
396             if (rtn != NULL)
397                 free(rtn);
398         }
399     }
400 
401     if (otn->proto_nodes)
402         free(otn->proto_nodes);
403 
404     if (otn->detection_filter)
405         free(otn->detection_filter);
406 
407     if (otn->preproc_fp_list != NULL)
408         FreePmdList(otn->preproc_fp_list);
409 
410     free(otn);
411 }
412 
OtnLookupNew(void)413 SFGHASH * OtnLookupNew(void)
414 {
415     return sfghash_new(10000, sizeof(OtnKey), 0, OtnFree);
416 }
417 
OtnLookupAdd(SFGHASH * otn_map,OptTreeNode * otn)418 void OtnLookupAdd(SFGHASH *otn_map, OptTreeNode *otn)
419 {
420     int status;
421     OtnKey key;
422 
423     if (otn_map == NULL)
424         return;
425 
426     key.gid = otn->sigInfo.generator;
427     key.sid = otn->sigInfo.id;
428 
429     status = sfghash_add(otn_map, &key, otn);
430     switch (status)
431     {
432         case SFGHASH_OK:
433             /* otn was inserted successfully */
434             break;
435 
436         case SFGHASH_INTABLE:
437             /* Assume it's a rule without an sid */
438             if (key.sid == 0)
439             {
440                 ParseError("Duplicate rule with same gid (%u) and no sid.  To "
441                            "avoid this, make sure all of your rules define an "
442                            "sid.\n", key.gid);
443             }
444             else
445             {
446                 ParseError("Duplicate rule with same gid (%u) and sid (%u)\n",
447                            key.gid, key.sid);
448             }
449 
450             break;
451 
452         case SFGHASH_NOMEM:
453             FatalError("Failed to allocate memory for rule.\n");
454             break;
455 
456         default:
457             FatalError("%s(%d): OtnLookupAdd() - unexpected return value "
458                        "from sfghash_add().\n", __FILE__, __LINE__);
459             break;
460     }
461 }
462 
OtnLookup(SFGHASH * otn_map,uint32_t gid,uint32_t sid)463 OptTreeNode * OtnLookup(SFGHASH *otn_map, uint32_t gid, uint32_t sid)
464 {
465     OptTreeNode * otn;
466     OtnKey key;
467 
468     if (otn_map == NULL)
469         return NULL;
470 
471     key.gid = gid;
472     key.sid = sid;
473 
474     otn = (OptTreeNode *)sfghash_find(otn_map, &key);
475 
476     return otn;
477 }
478 
OtnLookupFree(SFGHASH * otn_map)479 void OtnLookupFree(SFGHASH *otn_map)
480 {
481     if (otn_map == NULL)
482         return;
483 
484     sfghash_delete(otn_map);
485 }
486 
487 
488 /***************** End of Class/Priority Implementation ***********************/
489 
490