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