1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2004-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation.  You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //--------------------------------------------------------------------------
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "main/snort_config.h"
25 #include "managers/inspector_manager.h"
26 #include "profiler/profiler.h"
27 #include "protocols/packet.h"
28 #include "stream/stream.h"
29 #include "target_based/snort_protocols.h"
30 #include "utils/util.h"
31 
32 #include "ft_main.h"
33 #include "ftp_cmd_lookup.h"
34 #include "ftp_data.h"
35 #include "ftp_module.h"
36 #include "ftp_parse.h"
37 #include "ftp_print.h"
38 #include "ftp_splitter.h"
39 #include "ftpp_return_codes.h"
40 #include "ftpp_si.h"
41 #include "pp_ftp.h"
42 #include "telnet.h"
43 
44 using namespace snort;
45 
46 SnortProtocolId ftp_data_snort_protocol_id = UNKNOWN_PROTOCOL_ID;
47 
48 #define client_help "FTP inspector client module"
49 #define server_help "FTP inspector server module"
50 
51 THREAD_LOCAL ProfileStats ftpPerfStats;
52 THREAD_LOCAL FtpStats ftstats;
53 
54 //-------------------------------------------------------------------------
55 // implementation stuff
56 //-------------------------------------------------------------------------
57 
InspectClientPacket(Packet * p)58 static inline int InspectClientPacket(Packet* p)
59 {
60     return p->has_paf_payload();
61 }
62 
SnortFTP(FTP_SESSION * FTPsession,Packet * p,int iInspectMode)63 static int SnortFTP(
64     FTP_SESSION* FTPsession, Packet* p, int iInspectMode)
65 {
66     Profile profile(ftpPerfStats);
67 
68     if ( !FTPsession || !FTPsession->server_conf || !FTPsession->client_conf )
69         return FTPP_INVALID_SESSION;
70 
71     if ( !FTPsession->server_conf->check_encrypted_data )
72     {
73         if ( FTPsession->encr_state == AUTH_TLS_ENCRYPTED ||
74              FTPsession->encr_state == AUTH_SSL_ENCRYPTED ||
75              FTPsession->encr_state == AUTH_UNKNOWN_ENCRYPTED )
76 
77             return FTPP_SUCCESS;
78     }
79 
80     if (iInspectMode == FTPP_SI_SERVER_MODE)
81     {
82         // FIXIT-L breaks target-based non-standard ports
83         //if ( !ScPafEnabled() )
84         Stream::flush_client(p);
85     }
86     else if ( !InspectClientPacket(p) )
87         return FTPP_SUCCESS;
88 
89     int ret = initialize_ftp(FTPsession, p, iInspectMode);
90     if ( ret )
91         return ret;
92 
93     ret = check_ftp(FTPsession, p, iInspectMode);
94     if ( ret == FTPP_SUCCESS )
95     {
96         // FIXIT-L ideally do_detection will look at the cmd & param buffers
97         // or the rsp & msg buffers.  We should call it from inside check_ftp
98         // each time we process a pipelined FTP command.
99 
100         do_detection(p);
101     }
102 
103     return ret;
104 }
105 
snort_ftp(Packet * p)106 static int snort_ftp(Packet* p)
107 {
108     FTPP_SI_INPUT SiInput;
109     int iInspectMode = FTPP_SI_NO_MODE;
110     FTP_TELNET_SESSION* ft_ssn = nullptr;
111 
112     /*
113      * Set up the FTPP_SI_INPUT pointer.  This is what the session_inspection()
114      * routines use to determine client and server traffic.  Plus, this makes
115      * the FTPTelnet library very independent from snort.
116      */
117     SetSiInput(&SiInput, p);
118 
119     ftstats.total_bytes += p->dsize;
120     if (p->flow)
121     {
122         FtpFlowData* fd = (FtpFlowData*)p->flow->get_flow_data(FtpFlowData::inspector_id);
123         ft_ssn = fd ? &fd->session.ft_ssn : nullptr;
124 
125         if (ft_ssn != nullptr)
126         {
127             SiInput.pproto = ft_ssn->proto;
128 
129             if (ft_ssn->proto == FTPP_SI_PROTO_FTP)
130             {
131                 if (SiInput.pdir != FTPP_SI_NO_MODE)
132                 {
133                     iInspectMode = SiInput.pdir;
134                 }
135                 else
136                 {
137                     if ( p->is_from_server() )
138                     {
139                         iInspectMode = FTPP_SI_SERVER_MODE;
140                     }
141                     else if ( p->is_from_client() )
142                     {
143                         iInspectMode = FTPP_SI_CLIENT_MODE;
144                     }
145                     else
146                     {
147                         iInspectMode = FTPGetPacketDir(p);
148                     }
149                 }
150             }
151             else
152             {
153                 /* Not FTP or Telnet */
154                 assert(false);
155                 p->flow->free_flow_data(FtpFlowData::inspector_id);
156                 return 0;
157             }
158         }
159     }
160 
161     if (ft_ssn == nullptr)
162     {
163         SiInput.pproto = FTPP_SI_PROTO_UNKNOWN;
164         iInspectMode = FTPP_SI_NO_MODE;
165 
166         FTPsessionInspection(p, (FTP_SESSION**)&ft_ssn, &SiInput, &iInspectMode);
167 
168         if ( SiInput.pproto != FTPP_SI_PROTO_FTP )
169             return FTPP_INVALID_PROTO;
170     }
171 
172     if (ft_ssn != nullptr)
173     {
174         switch (SiInput.pproto)
175         {
176         case FTPP_SI_PROTO_FTP:
177             return SnortFTP((FTP_SESSION*)ft_ssn, p, iInspectMode);
178         }
179     }
180 
181     /* Uh, shouldn't get here  */
182     return FTPP_INVALID_PROTO;
183 }
184 
185 //-------------------------------------------------------------------------
186 // class stuff
187 //-------------------------------------------------------------------------
188 
189 class FtpClient : public Inspector
190 {
191 public:
FtpClient(FTP_CLIENT_PROTO_CONF * client)192     FtpClient(FTP_CLIENT_PROTO_CONF* client) : ftp_client(client) { }
193 
~FtpClient()194     ~FtpClient() override
195     { delete ftp_client; }
196 
197     void show(const SnortConfig*) const override;
eval(Packet *)198     void eval(Packet*) override { }
199 
200     FTP_CLIENT_PROTO_CONF* ftp_client;
201 };
202 
show(const SnortConfig *) const203 void FtpClient::show(const SnortConfig*) const
204 {
205     if ( ftp_client )
206         print_conf_client(ftp_client);
207 }
208 
209 class FtpServer : public Inspector
210 {
211 public:
212     FtpServer(FTP_SERVER_PROTO_CONF*);
213     ~FtpServer() override;
214 
215     bool configure(SnortConfig*) override;
216     void show(const SnortConfig*) const override;
217     void eval(Packet*) override;
218     StreamSplitter* get_splitter(bool) override;
219 
is_control_channel() const220     bool is_control_channel() const override
221     { return true; }
222 
can_start_tls() const223     bool can_start_tls() const override
224     { return true; }
225 
226     FTP_SERVER_PROTO_CONF* ftp_server;
227 };
228 
FtpServer(FTP_SERVER_PROTO_CONF * server)229 FtpServer::FtpServer(FTP_SERVER_PROTO_CONF* server) :
230     ftp_server(server)
231 {}
232 
~FtpServer()233 FtpServer::~FtpServer ()
234 {
235     CleanupFTPServerConf(ftp_server);
236     delete ftp_server;
237 }
238 
configure(SnortConfig * sc)239 bool FtpServer::configure(SnortConfig* sc)
240 {
241     ftp_data_snort_protocol_id = sc->proto_ref->add("ftp-data");
242     return !FTPCheckConfigs(sc, ftp_server);
243 }
244 
show(const SnortConfig *) const245 void FtpServer::show(const SnortConfig*) const
246 {
247     if ( ftp_server )
248         print_conf_server(ftp_server);
249 }
250 
get_splitter(bool c2s)251 StreamSplitter* FtpServer::get_splitter(bool c2s)
252 {
253     return new FtpSplitter(c2s);
254 }
255 
eval(Packet * p)256 void FtpServer::eval(Packet* p)
257 {
258     // precondition - what we registered for
259     assert(p->has_tcp_data());
260 
261     ++ftstats.total_packets;
262     snort_ftp(p);
263 }
264 
265 //-------------------------------------------------------------------------
266 // get the relevant configs required by legacy ftp code
267 // the client must be found if not explicitly bound
268 
get_ftp_client(Packet * p)269 FTP_CLIENT_PROTO_CONF* get_ftp_client(Packet* p)
270 {
271     FtpClient* client = (FtpClient*)p->flow->data;
272     if ( !client )
273     {
274         client = (FtpClient*)InspectorManager::get_inspector(FTP_CLIENT_NAME);
275         assert(client);
276         p->flow->set_data(client);
277     }
278     return client->ftp_client;
279 }
280 
get_ftp_server(Packet * p)281 FTP_SERVER_PROTO_CONF* get_ftp_server(Packet* p)
282 {
283     FtpServer* server = (FtpServer*)p->flow->gadget;
284     assert(server);
285     return server->ftp_server;
286 }
287 
288 //-------------------------------------------------------------------------
289 // api stuff
290 //
291 // fc_ = ftp_client
292 // fs_ = ftp_server
293 //-------------------------------------------------------------------------
294 
fc_mod_ctor()295 static Module* fc_mod_ctor()
296 { return new FtpClientModule; }
297 
298 // this can be used for both modules
mod_dtor(Module * m)299 static void mod_dtor(Module* m)
300 { delete m; }
301 
fc_ctor(Module * m)302 static Inspector* fc_ctor(Module* m)
303 {
304     FtpClientModule* mod = (FtpClientModule*)m;
305     FTP_CLIENT_PROTO_CONF* gc = mod->get_data();
306     unsigned i = 0;
307 
308     while ( const BounceTo* bt = mod->get_bounce(i++) )
309     {
310         ProcessFTPAllowBounce(
311             gc, (const uint8_t*)bt->address.c_str(), bt->address.size(), bt->low, bt->high);
312     }
313     return new FtpClient(gc);
314 }
315 
fc_dtor(Inspector * p)316 static void fc_dtor(Inspector* p)
317 { delete p; }
318 
319 static const InspectApi fc_api =
320 {
321     {
322         PT_INSPECTOR,
323         sizeof(InspectApi),
324         INSAPI_VERSION,
325         0,
326         API_RESERVED,
327         API_OPTIONS,
328         FTP_CLIENT_NAME,
329         client_help,
330         fc_mod_ctor,
331         mod_dtor
332     },
333     IT_PASSIVE,
334     PROTO_BIT__NONE,
335     nullptr, // buffers
336     "ftp",
337     nullptr, // init,
338     nullptr, // pterm
339     nullptr, // tinit
340     nullptr, // tterm
341     fc_ctor,
342     fc_dtor,
343     nullptr, // ssn
344     nullptr  // reset
345 };
346 
347 //-------------------------------------------------------------------------
348 
fs_mod_ctor()349 static Module* fs_mod_ctor()
350 { return new FtpServerModule; }
351 
fs_init()352 static void fs_init()
353 {
354     FtpFlowData::init();
355 }
356 
fs_ctor(Module * mod)357 static Inspector* fs_ctor(Module* mod)
358 {
359     FtpServerModule* fsm = (FtpServerModule*)mod;
360     FTP_SERVER_PROTO_CONF* conf = fsm->get_data();
361 
362     return new FtpServer(conf);
363 }
364 
fs_dtor(Inspector * p)365 static void fs_dtor(Inspector* p)
366 {
367     delete p;
368 }
369 
370 static const InspectApi fs_api =
371 {
372     {
373         PT_INSPECTOR,
374         sizeof(InspectApi),
375         INSAPI_VERSION,
376         0,
377         API_RESERVED,
378         API_OPTIONS,
379         FTP_SERVER_NAME,
380         server_help,
381         fs_mod_ctor,
382         mod_dtor
383     },
384     IT_SERVICE,
385     PROTO_BIT__PDU,
386     nullptr, // buffers
387     "ftp",
388     fs_init,
389     nullptr, // pterm
390     nullptr, // tinit
391     nullptr, // tterm
392     fs_ctor,
393     fs_dtor,
394     nullptr, // ssn
395     nullptr  // reset
396 };
397 
398 #ifdef BUILDING_SO
399 SO_PUBLIC const BaseApi* snort_plugins[] =
400 {
401     &fc_api.base,
402     &fs_api.base,
403     &fd_api.base,
404     &tn_api.base,
405     nullptr
406 };
407 #else
408 const BaseApi* sin_telnet = &tn_api.base;
409 const BaseApi* sin_ftp_client = &fc_api.base;
410 const BaseApi* sin_ftp_server = &fs_api.base;
411 const BaseApi* sin_ftp_data = &fd_api.base;
412 #endif
413 
414