1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // action_manager.cc author Russ Combs <rucombs@cisco.com>
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "action_manager.h"
25 
26 #include <vector>
27 
28 #include "log/messages.h"
29 #include "main/snort_config.h"
30 #include "managers/module_manager.h"
31 #include "managers/plugin_manager.h"
32 #include "packet_io/active.h"
33 #include "parser/parser.h"
34 
35 using namespace snort;
36 using namespace std;
37 
38 struct ActionClass
39 {
40     const ActionApi* api;
41     bool initialized = false;   // In the context of the main thread, this means that api.pinit()
42                                 // has been called.  In the packet thread, it means that api.tinit()
43                                 // has been called.
44 
ActionClassActionClass45     ActionClass(const ActionApi* p) : api(p) { }
46 };
47 
48 struct ActionInst
49 {
50     ActionClass& cls;
51     IpsAction* act;
52 
ActionInstActionInst53     ActionInst(ActionClass& cls, IpsAction* act) : cls(cls), act(act) { }
54 };
55 
56 struct IpsActionsConfig
57 {
58     vector<ActionInst> clist;
59 };
60 
61 using ACList = vector<ActionClass>;
62 using ACTypeList = unordered_map<string, Actions::Type>;
63 using ACPriorityList = map<IpsAction::IpsActionPriority, string, std::greater<int>>;
64 
65 static ACList s_actors;
66 static ACTypeList s_act_types;
67 static ACPriorityList s_act_priorities;
68 static Actions::Type s_act_index = 0;
69 
70 static THREAD_LOCAL ACList* s_tl_actors = nullptr;
71 
72 //-------------------------------------------------------------------------
73 // Main thread operations
74 //-------------------------------------------------------------------------
75 
76 // Plugin/Class operations
add_plugin(const ActionApi * api)77 void ActionManager::add_plugin(const ActionApi* api)
78 {
79     s_actors.emplace_back(api);
80     s_act_types.emplace(api->base.name, s_act_index++);
81     s_act_priorities.emplace(api->priority, api->base.name);
82 }
83 
get_action_string(Actions::Type action)84 std::string ActionManager::get_action_string(Actions::Type action)
85 {
86     if ( action < s_act_index )
87     {
88         for ( const auto& type : s_act_types )
89         {
90             if ( type.second == action )
91                 return type.first;
92         }
93     }
94 
95     return "ERROR";
96 }
97 
get_action_type(const char * s)98 Actions::Type ActionManager::get_action_type(const char* s)
99 {
100     auto type = s_act_types.find(s);
101 
102     if (type != s_act_types.end())
103         return type->second;
104 
105     return get_max_action_types();
106 }
107 
get_max_action_types()108 Actions::Type ActionManager::get_max_action_types()
109 {
110     return s_act_index;
111 }
112 
get_action_priorities(bool alert_before_pass)113 std::string ActionManager::get_action_priorities(bool alert_before_pass)
114 {
115     std::string priorities;
116 
117     for (auto iter = s_act_priorities.begin(); iter != s_act_priorities.end(); )
118     {
119         if ( alert_before_pass )
120         {
121             if ( iter->second == "pass" )
122             {
123                 iter++;
124                 continue;
125             }
126             else if ( iter->second == "alert" )
127             {
128                 priorities += "alert pass ";
129                 iter++;
130                 continue;
131             }
132         }
133 
134         priorities += iter->second;
135 
136         if ( ++iter != s_act_priorities.end() )
137             priorities += " ";
138     }
139 
140     return priorities;
141 }
142 
dump_plugins()143 void ActionManager::dump_plugins()
144 {
145     Dumper d("IPS Actions");
146 
147     for ( auto& p : s_actors )
148         d.dump(p.api->base.name, p.api->base.version);
149 }
150 
release_plugins()151 void ActionManager::release_plugins()
152 {
153     for ( auto& p : s_actors )
154     {
155         if ( p.api->pterm )
156             p.api->pterm();
157     }
158     s_actors.clear();
159 }
160 
get_action_class(const ActionApi * api,IpsActionsConfig * iac)161 static ActionClass* get_action_class(const ActionApi* api, IpsActionsConfig* iac)
162 {
163     for ( auto& ai : iac->clist )
164     {
165         if ( ai.cls.api == api )
166             return &ai.cls;
167     }
168 
169     for ( auto& ac : s_actors )
170     {
171         if ( ac.api == api )
172         {
173             if ( !ac.initialized )
174             {
175                 if ( ac.api->pinit )
176                     ac.api->pinit();
177                 ac.initialized = true;
178             }
179             return &ac;
180         }
181     }
182 
183     return nullptr;
184 }
185 
186 // Config operations
new_config(SnortConfig * sc)187 void ActionManager::new_config(SnortConfig* sc)
188 {
189     sc->ips_actions_config = new IpsActionsConfig;
190 }
191 
delete_config(SnortConfig * sc)192 void ActionManager::delete_config(SnortConfig* sc)
193 {
194     if (!sc->ips_actions_config)
195         return;
196 
197     // Delete all IPS action instances that were created as part of this configuration
198     for (auto& ia : sc->ips_actions_config->clist)
199         ia.cls.api->dtor(ia.act);
200 
201     delete sc->ips_actions_config;
202     sc->ips_actions_config = nullptr;
203 }
204 
instantiate(const ActionApi * api,Module * mod,SnortConfig * sc,IpsPolicy * ips)205 void ActionManager::instantiate(const ActionApi* api, Module* mod, SnortConfig* sc, IpsPolicy* ips)
206 {
207     ActionClass* cls = get_action_class(api, sc->ips_actions_config);
208 
209     assert(cls != nullptr);
210 
211     IpsAction* act = cls->api->ctor(mod);
212 
213     if ( act )
214     {
215 
216         RuleListNode* rln = CreateRuleType(sc, api->base.name, get_action_type(api->base.name));
217 
218         // The plugin actions (e.g. reject, react, etc.) are per policy, per mode.
219         // At logging time, they have to be retrieved the way we store them here.
220         if ( !ips )
221             ips = get_ips_policy();
222 
223         Actions::Type idx = rln->mode;
224         if (ips->action[idx] == nullptr)
225         {
226             ips->action[idx] = act;
227             // Add this instance to the list of those created for this config
228             sc->ips_actions_config->clist.emplace_back(*cls, act);
229         }
230         else
231         {
232             cls->api->dtor(act);
233         }
234     }
235 }
236 
initialize_policies(SnortConfig * sc)237 void ActionManager::initialize_policies(SnortConfig* sc)
238 {
239     for (unsigned i = 0; i < sc->policy_map->ips_policy_count(); i++)
240     {
241         auto policy = sc->policy_map->get_ips_policy(i);
242 
243         if ( !policy )
244             continue;
245 
246         for ( auto actor : s_actors )
247             ActionManager::instantiate(actor.api, nullptr, sc, policy);
248     }
249 }
250 
251 //-------------------------------------------------------------------------
252 // Packet thread operations
253 //-------------------------------------------------------------------------
get_thread_local_action_class(const ActionApi * api)254 static ActionClass& get_thread_local_action_class(const ActionApi* api)
255 {
256     for ( ActionClass& p : *s_tl_actors )
257     {
258         if ( p.api == api )
259             return p;
260     }
261     s_tl_actors->emplace_back(api);
262     return s_tl_actors->back();
263 }
264 
thread_init(const SnortConfig * sc)265 void ActionManager::thread_init(const SnortConfig* sc)
266 {
267     // Initial build out of this thread's configured plugin registry
268     s_tl_actors = new ACList;
269     for ( auto& p : sc->ips_actions_config->clist )
270     {
271         ActionClass& tlac = get_thread_local_action_class(p.cls.api);
272         if ( tlac.api->tinit )
273             tlac.api->tinit();
274         tlac.initialized = true;
275     }
276 }
277 
thread_reinit(const SnortConfig * sc)278 void ActionManager::thread_reinit(const SnortConfig* sc)
279 {
280     // Update this thread's configured plugin registry with any newly configured inspectors
281     for ( auto& p : sc->ips_actions_config->clist )
282     {
283         ActionClass& tlac = get_thread_local_action_class(p.cls.api);
284         if (!tlac.initialized)
285         {
286             if ( tlac.api->tinit )
287                 tlac.api->tinit();
288             tlac.initialized = true;
289         }
290     }
291     Active::thread_init(sc);
292 }
293 
thread_term()294 void ActionManager::thread_term()
295 {
296     if (s_tl_actors)
297     {
298         // Call tterm for every IPS action plugin ever configured during the lifetime of this thread
299         for ( auto& p : *s_tl_actors )
300         {
301             if ( p.api->tterm )
302                 p.api->tterm();
303         }
304         delete s_tl_actors;
305         s_tl_actors = nullptr;
306     }
307 }
308 
309 #ifdef PIGLET
310 
311 //-------------------------------------------------------------------------
312 // piglet breach
313 //-------------------------------------------------------------------------
314 
find_api(const char * name)315 static const ActionApi* find_api(const char* name)
316 {
317     for ( auto actor : s_actors )
318         if ( !strcmp(actor.api->base.name, name) )
319             return actor.api;
320 
321     return nullptr;
322 }
323 
instantiate(const char * name,Module * m)324 IpsActionWrapper* ActionManager::instantiate(const char* name, Module* m)
325 {
326     auto api = find_api(name);
327     if ( !api || !api->ctor )
328         return nullptr;
329 
330     auto p = api->ctor(m);
331     if ( !p )
332         return nullptr;
333 
334     return new IpsActionWrapper(api, p);
335 }
336 
337 #endif
338 
339