1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 // Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
5 // Copyright (C) 2000,2001 Andrew R. Baker <andrewb@uab.edu>
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License Version 2 as published
9 // by the Free Software Foundation.  You may not use, modify or distribute
10 // this program under any other version of the GNU General Public License.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program; if not, write to the Free Software Foundation, Inc.,
19 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //--------------------------------------------------------------------------
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "parse_conf.h"
27 
28 #include <sys/stat.h>
29 #include <unistd.h>
30 
31 #include <cassert>
32 #include <climits>
33 #include <fstream>
34 #include <stack>
35 
36 #include "log/messages.h"
37 #include "main/snort_config.h"
38 #include "managers/module_manager.h"
39 #include "sfip/sf_vartable.h"
40 #include "target_based/snort_protocols.h"
41 #include "utils/util.h"
42 
43 #include "config_file.h"
44 #include "parser.h"
45 #include "parse_stream.h"
46 #include "vars.h"
47 
48 using namespace snort;
49 
50 struct Location
51 {
52     const char* code;
53     std::string path;
54     std::string file;
55     unsigned line;
56 
LocationLocation57     Location(const char* c, const char* p, const char* f, unsigned u)
58     { code = c; path = p; file = f; line = u; }
59 };
60 
61 static std::stack<Location> files;
62 static int rules_file_depth = 0;
63 
get_parse_file()64 const char* get_parse_file()
65 {
66     if ( !files.empty() )
67         return files.top().path.c_str();
68 
69     return get_snort_conf();
70 }
71 
get_parse_location(const char * & file,unsigned & line)72 void get_parse_location(const char*& file, unsigned& line)
73 {
74     if ( files.empty() )
75     {
76         file = nullptr;
77         line = 0;
78         return;
79     }
80     Location& loc = files.top();
81     file = loc.file.c_str();
82     line = loc.line;
83 }
84 
print_parse_file(const char * msg,Location & loc)85 static void print_parse_file(const char* msg, Location& loc)
86 {
87     if ( SnortConfig::get_conf()->show_file_codes() )
88         LogMessage("%s %s:%s:\n", msg, (loc.code ? loc.code : "?"), loc.file.c_str());
89 
90     else
91         LogMessage("%s %s:\n", msg, loc.file.c_str());
92 }
93 
push_parse_location(const char * code,const char * path,const char * file,unsigned line)94 void push_parse_location(
95     const char* code, const char* path, const char* file, unsigned line)
96 {
97     if ( !path )
98         return;
99 
100     if ( !file )
101         file = path;
102 
103     Location loc(code, path, file, line);
104     files.push(loc);
105     print_parse_file("Loading", loc);
106 }
107 
pop_parse_location()108 void pop_parse_location()
109 {
110     if ( !files.empty() )
111     {
112         Location& loc = files.top();
113         print_parse_file("Finished", loc);
114         files.pop();
115     }
116 }
117 
inc_parse_position()118 void inc_parse_position()
119 {
120     if ( files.empty() )
121         return;
122     Location& loc = files.top();
123     ++loc.line;
124 }
125 
valid_file(const char * file,std::string & path)126 static bool valid_file(const char* file, std::string& path)
127 {
128     path += '/';
129     path += file;
130 
131     struct stat s;
132     return stat(path.c_str(), &s) == 0;
133 }
134 
relative_to_parse_dir(const char * file,std::string & path)135 static bool relative_to_parse_dir(const char* file, std::string& path)
136 {
137     if ( !path.length() )
138         path = get_parse_file();
139     size_t idx = path.rfind('/');
140     if ( idx != std::string::npos )
141         path.erase(idx);
142     else
143         path = ".";
144     return valid_file(file, path);
145 }
146 
relative_to_config_dir(const char * file,std::string & path)147 static bool relative_to_config_dir(const char* file, std::string& path)
148 {
149     path = get_snort_conf_dir();
150     return valid_file(file, path);
151 }
152 
relative_to_include_dir(const char * file,std::string & path)153 static bool relative_to_include_dir(const char* file, std::string& path)
154 {
155     path = SnortConfig::get_conf()->include_path;
156     if ( !path.length() )
157         return false;
158     return valid_file(file, path);
159 }
160 
get_config_file(const char * arg,std::string & file)161 const char* get_config_file(const char* arg, std::string& file)
162 {
163     bool absolute = (arg[0] == '/');
164 
165     if ( absolute )
166     {
167         file = arg;
168         return "A";
169     }
170     std::string hint = file;
171 
172     if ( relative_to_include_dir(arg, file) )
173         return "I";
174 
175     file = hint;
176 
177     if ( relative_to_parse_dir(arg, file) )
178         return "F";
179 
180     if ( relative_to_config_dir(arg, file) )
181         return "C";
182 
183     return nullptr;
184 }
185 
parse_include(SnortConfig * sc,const char * arg)186 void parse_include(SnortConfig* sc, const char* arg)
187 {
188     assert(arg);
189     arg = ExpandVars(arg);
190     std::string file = !rules_file_depth ? get_ips_policy()->includer : get_parse_file();
191 
192     const char* code = get_config_file(arg, file);
193 
194     if ( !code )
195     {
196         ParseError("can't open %s\n", arg);
197         return;
198     }
199     push_parse_location(code, file.c_str(), arg);
200     parse_rules_file(sc, file.c_str());
201     pop_parse_location();
202 }
203 
ParseIpVar(const char * var,const char * value)204 void ParseIpVar(const char* var, const char* value)
205 {
206     int ret;
207     IpsPolicy* p = get_ips_policy();  // FIXIT-M double check, see below
208     DisallowCrossTableDuplicateVars(var, VAR_TYPE__IPVAR);
209 
210     if ((ret = sfvt_define(p->ip_vartable, var, value)) != SFIP_SUCCESS)
211     {
212         switch (ret)
213         {
214         case SFIP_ARG_ERR:
215             ParseError("the following is not allowed: %s.", value);
216             return;
217 
218         case SFIP_DUPLICATE:
219             ParseWarning(WARN_VARS, "Var '%s' redefined.", var);
220             break;
221 
222         case SFIP_CONFLICT:
223             ParseError("negated IP ranges that are more general than "
224                 "non-negated ranges are not allowed. Consider "
225                 "inverting the logic in %s.", var);
226             return;
227 
228         case SFIP_NOT_ANY:
229             ParseError("!any is not allowed in %s.", var);
230             return;
231 
232         default:
233             ParseError("failed to parse the IP address: %s.", value);
234             return;
235         }
236     }
237 }
238 
add_service_to_otn(SnortConfig * sc,OptTreeNode * otn,const char * svc_name)239 void add_service_to_otn(SnortConfig* sc, OptTreeNode* otn, const char* svc_name)
240 {
241     if ( !strcmp(svc_name, "file") and otn->sigInfo.services.empty() )
242     {
243         // well-known services supporting file_data
244         // applies to both alert file and service:file rules
245         add_service_to_otn(sc, otn, "ftp-data");
246         add_service_to_otn(sc, otn, "netbios-ssn");
247         add_service_to_otn(sc, otn, "http");
248         add_service_to_otn(sc, otn, "pop3");
249         add_service_to_otn(sc, otn, "imap");
250         add_service_to_otn(sc, otn, "smtp");
251         add_service_to_otn(sc, otn, "file");
252         return;
253     }
254 
255     if ( !strcmp(svc_name, "http") )
256         add_service_to_otn(sc, otn, "http2");
257 
258     SnortProtocolId svc_id = sc->proto_ref->add(svc_name);
259 
260     for ( const auto& si : otn->sigInfo.services )
261         if ( si.snort_protocol_id == svc_id )
262             return;  // already added
263 
264     SignatureServiceInfo si(svc_name, svc_id);
265     otn->sigInfo.services.emplace_back(si);
266 }
267 
get_rule_list(SnortConfig * sc,const char * s)268 ListHead* get_rule_list(SnortConfig* sc, const char* s)
269 {
270     const RuleListNode* p = sc->rule_lists;
271 
272     while ( p && strcmp(p->name, s) )
273         p = p->next;
274 
275     return p ? p->RuleList : nullptr;
276 }
277 
parse_rules_file(SnortConfig * sc,const char * fname)278 void parse_rules_file(SnortConfig* sc, const char* fname)
279 {
280     if ( !fname )
281         return;
282 
283     std::ifstream fs(fname, std::ios_base::binary);
284 
285     if ( !fs )
286     {
287         ParseError("unable to open rules file '%s': %s",
288             fname, get_error(errno));
289         return;
290     }
291     ++rules_file_depth;
292     parse_stream(fs, sc);
293     --rules_file_depth;
294 }
295 
parse_rules_string(SnortConfig * sc,const char * s)296 void parse_rules_string(SnortConfig* sc, const char* s)
297 {
298     std::string rules = s;
299     std::stringstream ss(rules);
300     parse_stream(ss, sc);
301 }
302 
303