1 /*
2  * spp_ftptelnet.c
3  *
4  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5  * Copyright (C) 2004-2013 Sourcefire, Inc.
6  * Steven A. Sturges <ssturges@sourcefire.com>
7  * Daniel J. Roelker <droelker@sourcefire.com>
8  * Marc A. Norton <mnorton@sourcefire.com>
9  * Kevin Liu <kliu@sourcefire.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License Version 2 as
13  * published by the Free Software Foundation.  You may not use, modify or
14  * distribute this program under any other version of the GNU General
15  * Public License.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
25  *
26  * Description:
27  *
28  * This file initializes FTPTelnet as a Snort preprocessor.
29  *
30  * This file registers the FTPTelnet initialization function,
31  * adds the FTPTelnet function into the preprocessor list, reads
32  * the user configuration in the snort.conf file, and prints out
33  * the configuration that is read.
34  *
35  * In general, this file is a wrapper to FTPTelnet functionality,
36  * by interfacing with the Snort preprocessor functions.  The rest
37  * of FTPTelnet should be separate from the preprocessor hooks.
38  *
39  * NOTES:
40  * - 16.09.04:  Initial Development.  SAS
41  *
42  */
43 
44 #include <assert.h>
45 #include <string.h>
46 #include <stdio.h>
47 #include <sys/types.h>
48 #include <time.h>
49 
50 #ifdef HAVE_CONFIG_H
51 #include "config.h"
52 #endif
53 
54 #include "sf_types.h"
55 #include "snort_debug.h"
56 
57 #include "ftpp_ui_config.h"
58 #include "snort_ftptelnet.h"
59 #include "spp_ftptelnet.h"
60 #include "sf_preproc_info.h"
61 
62 #include "profiler.h"
63 
64 #include "sfPolicy.h"
65 #include "sfPolicyUserData.h"
66 #ifdef REG_TEST
67 #include "ftpp_si.h"
68 #endif
69 
70 #ifdef DUMP_BUFFER
71 #include "ftptelnet_buffer_dump.h"
72 #endif
73 
74 #include "reg_test.h"
75 #include "memory_stats.h"
76 
77 const int MAJOR_VERSION = 1;
78 const int MINOR_VERSION = 2;
79 const int BUILD_VERSION = 13;
80 const char *PREPROC_NAME = "SF_FTPTELNET";
81 
82 #define SetupFTPTelnet DYNAMIC_PREPROC_SETUP
83 
84 
85 /*
86  * Defines for preprocessor initialization
87  */
88 /*
89  * snort.conf preprocessor keyword
90  */
91 #define GLOBAL_KEYWORD   "ftp_telnet"
92 #define PROTOCOL_KEYWORD "ftp_telnet_protocol"
93 
94 /*
95  * The length of the error string buffer.
96  */
97 #define ERRSTRLEN 1000
98 
99 /*
100  * External Global Variables
101  * Variables that we need from Snort to log errors correctly and such.
102  */
103 #ifdef PERF_PROFILING
104 PreprocStats ftpPerfStats;
105 PreprocStats telnetPerfStats;
106 #ifdef TARGET_BASED
107 PreprocStats ftpdataPerfStats;
108 #endif
109 #endif
110 FTPTelnet_Stats ftp_telnet_stats;
111 
112 /*
113  * Global Variables
114  * This is the only way to work with Snort preprocessors because
115  * the user configuration must be kept between the Init function
116  * the actual preprocessor.  There is no interaction between the
117  * two except through global variable usage.
118  */
119 tSfPolicyUserContextId ftp_telnet_config = NULL;
120 FTPTELNET_GLOBAL_CONF *ftp_telnet_eval_config = NULL;
121 
122 #ifdef TARGET_BASED
123 int16_t ftp_app_id = 0;
124 int16_t ftp_data_app_id = 0;
125 int16_t telnet_app_id = 0;
126 #endif
127 
128 /* static function prototypes */
129 static void FTPTelnetReset(int, void *);
130 static void FTPTelnetResetStats(int, void *);
131 static void FTPTelnetStats(int);
132 
133 #ifdef SNORT_RELOAD
134 static void FtpTelnetReloadGlobal(struct _SnortConfig *, char *, void **);
135 static void FtpTelnetReload(struct _SnortConfig *, char *, void **);
136 static int FtpTelnetReloadVerify(struct _SnortConfig *, void *);
137 static void * FtpTelnetReloadSwap(struct _SnortConfig *, void *);
138 static void FtpTelnetReloadSwapFree(void *);
139 #endif
140 int ftptelnet_print_mem_stats(FILE *, char*, PreprocMemInfo *);
141 
142 extern char *maxToken;
143 
144 /*
145  * Function: FTPTelnetChecks(Packet *p)
146  *
147  * Purpose: This function wraps the functionality in the generic FTPTelnet
148  *          processing.  We get a Packet structure and pass this into the
149  *          FTPTelnet module where the first stage in FTPTelnet is the
150  *          Normalization stage where most of the other Snortisms are
151  *          taken care of.  After that, the modules are generic.
152  *
153  * Arguments: p         => pointer to a Packet structure that contains
154  *                         Snort info about the packet.
155  *
156  * Returns: None
157  *
158  */
FTPTelnetChecks(void * pkt,void * context)159 void FTPTelnetChecks(void *pkt, void *context)
160 {
161     SFSnortPacket *p = (SFSnortPacket*)pkt;
162 
163     // precondition - what we registered for
164     assert(IsTCP(p) && p->payload && p->payload_size);
165 
166     SnortFTPTelnet(p);
167 }
168 
169 #ifdef TARGET_BASED
FTPDataTelnetChecks(void * pkt,void * context)170 void FTPDataTelnetChecks(void *pkt, void *context)
171 {
172     SFSnortPacket *p = (SFSnortPacket*)pkt;
173 
174     // precondition - what we registered for
175     assert(IsTCP(p));
176 
177     if ( _dpd.fileAPI->get_max_file_depth(NULL, false) >= 0 )
178     {
179         if ( _dpd.sessionAPI->get_application_protocol_id(p->stream_session)
180             == ftp_data_app_id )
181         {
182             PROFILE_VARS;
183             PREPROC_PROFILE_START(ftpdataPerfStats);
184             SnortFTPData(p);
185             PREPROC_PROFILE_END(ftpdataPerfStats);
186             return;
187         }
188     }
189     if ( !p->payload_size || (p->payload == NULL) )
190         return;
191 
192     SnortFTPTelnet(p);
193 }
194 #endif
195 
196 /*
197  * Function: FTPTelnetInit(char *args)
198  *
199  * Purpose: This function cleans up FTPTelnet memory from the configuration
200  *          data.
201  *
202  * Arguments: sig       => signal causing this to be called
203  *            args      => pointer to a context strucutre
204  *
205  * Returns: None
206  *
207  */
FTPTelnetCleanExit(int sig,void * args)208 void FTPTelnetCleanExit(int sig, void *args)
209 {
210     FTPTelnetFreeConfigs(ftp_telnet_config);
211     ftp_telnet_config = NULL;
212 }
213 
214 /*
215  * Function: FTPTelnetInit(char *args)
216  *
217  * Purpose: This function initializes FTPTelnetInit with a user configuration.
218  *          The function is called when FTPTelnet is configured in snort.conf.
219  *          It gets passed a string of arguments, which gets parsed into
220  *          configuration constructs that FTPTelnet understands.
221  *
222  *          This function gets called for every FTPTelnet configure line.  We
223  *          use this characteristic to split up the configuration, so each
224  *          line is a configuration construct.  We need to keep track of what
225  *          part of the configuration has been configured, so we don't
226  *          configure one part, then configure it again.
227  *
228  *          Any upfront memory is allocated here (if necessary).
229  *
230  * Arguments: args      => pointer to a string to the preprocessor arguments.
231  *
232  * Returns: None
233  *
234  */
235 
236 extern char* mystrtok (char* s, const char* delim);
237 
238 #ifdef REG_TEST
PrintFTPSize(void)239 static inline void PrintFTPSize(void)
240 {
241     _dpd.logMsg("\nFTP Session Size: %lu\n", (long unsigned int)sizeof(FTP_SESSION));
242 }
243 #endif
244 
FTPTelnetInit(struct _SnortConfig * sc,char * args)245 static void FTPTelnetInit(struct _SnortConfig *sc, char *args)
246 {
247     char  *pcToken;
248     char ErrorString[ERRSTRLEN];
249     int iErrStrLen = ERRSTRLEN;
250     int iRet = 0;
251     tSfPolicyId policy_id = _dpd.getParserPolicy(sc);
252     FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL;
253 
254     ErrorString[0] = '\0';
255 
256 #ifdef REG_TEST
257     PrintFTPSize();
258 #endif
259 
260     if ((args == NULL) || (strlen(args) == 0))
261     {
262         DynamicPreprocessorFatalMessage("%s(%d) No arguments to FtpTelnet "
263                 "configuration.\n", *_dpd.config_file, *_dpd.config_line);
264     }
265 
266     /* Find out what is getting configured */
267     maxToken = args + strlen(args);
268     pcToken = mystrtok(args, CONF_SEPARATORS);
269     if (pcToken == NULL)
270     {
271         DynamicPreprocessorFatalMessage("%s(%d)mystrtok returned NULL when it "
272                                         "should not.", __FILE__, __LINE__);
273     }
274 
275     if (ftp_telnet_config == NULL)
276     {
277         //create a context
278         ftp_telnet_config = sfPolicyConfigCreate();
279 
280         if (ftp_telnet_config == NULL)
281         {
282             DynamicPreprocessorFatalMessage("No memory to allocate "
283                                             "FTP/Telnet configuration.\n");
284         }
285 
286         _dpd.addPreprocExit(FTPTelnetCleanExit, NULL, PRIORITY_APPLICATION, PP_FTPTELNET);
287         _dpd.addPreprocReset(FTPTelnetReset, NULL, PRIORITY_APPLICATION, PP_FTPTELNET);
288         _dpd.addPreprocResetStats(FTPTelnetResetStats, NULL, PRIORITY_APPLICATION, PP_FTPTELNET);
289         _dpd.addPreprocConfCheck(sc, FTPConfigCheck);
290         _dpd.registerPreprocStats("ftp_telnet", FTPTelnetStats);
291 
292 #ifdef PERF_PROFILING
293         _dpd.addPreprocProfileFunc("ftptelnet_ftp", (void*)&ftpPerfStats, 0, _dpd.totalPerfStats, NULL);
294         _dpd.addPreprocProfileFunc("ftptelnet_telnet", (void*)&telnetPerfStats, 0, _dpd.totalPerfStats, NULL);
295 #ifdef TARGET_BASED
296         _dpd.addPreprocProfileFunc("ftptelnet_ftpdata", (void*)&ftpdataPerfStats, 0, _dpd.totalPerfStats, NULL);
297 #endif
298 #endif
299 
300 #ifdef TARGET_BASED
301         if (_dpd.streamAPI != NULL)
302         {
303             /* Find and store the application ID for FTP & Telnet */
304             ftp_app_id = _dpd.addProtocolReference("ftp");
305             ftp_data_app_id = _dpd.addProtocolReference("ftp-data");
306             telnet_app_id = _dpd.addProtocolReference("telnet");
307         }
308 
309         // register with session to handle applications
310         _dpd.sessionAPI->register_service_handler( PP_FTPTELNET, ftp_app_id );
311         _dpd.sessionAPI->register_service_handler( PP_FTPTELNET, ftp_data_app_id );
312         _dpd.sessionAPI->register_service_handler( PP_FTPTELNET, telnet_app_id );
313 #endif
314     }
315 
316     /*
317      * Global Configuration Processing
318      * We only process the global configuration once, but always check for
319      * user mistakes, like configuring more than once.  That's why we
320      * still check for the global token even if it's been checked.
321      */
322     sfPolicyUserPolicySet (ftp_telnet_config, policy_id);
323     pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_config);
324     if (pPolicyConfig == NULL)
325     {
326         if (strcasecmp(pcToken, GLOBAL) != 0)
327         {
328             DynamicPreprocessorFatalMessage("%s(%d) Must configure the "
329                 "ftptelnet global configuration first.\n",
330                 *_dpd.config_file, *_dpd.config_line);
331         }
332 
333         pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)_dpd.snortAlloc(1,
334                                                   sizeof(FTPTELNET_GLOBAL_CONF),
335                                                   PP_FTPTELNET,
336                                                   PP_MEM_CATEGORY_CONFIG);
337 
338         if (pPolicyConfig == NULL)
339         {
340             DynamicPreprocessorFatalMessage("No memory to allocate "
341                                             "FTP/Telnet configuration.\n");
342         }
343 
344         sfPolicyUserDataSetCurrent(ftp_telnet_config, pPolicyConfig);
345 
346         iRet = FtpTelnetInitGlobalConfig(pPolicyConfig,
347                                          ErrorString, iErrStrLen);
348 
349         if (iRet == 0)
350         {
351             iRet = ProcessFTPGlobalConf(pPolicyConfig,
352                                      ErrorString, iErrStrLen);
353 
354             if (iRet == 0)
355             {
356                 PrintFTPGlobalConf(pPolicyConfig);
357 
358                 _dpd.preprocOptRegister(sc, "ftp.bounce", &FTPPBounceInit, &FTPPBounceEval,
359                         NULL, NULL, NULL, NULL, NULL);
360 
361 #ifdef TARGET_BASED
362                 if (_dpd.streamAPI != NULL)
363                 {
364                     _dpd.streamAPI->set_service_filter_status
365                         (sc, ftp_app_id, PORT_MONITOR_SESSION, policy_id, 1);
366 
367                     _dpd.streamAPI->set_service_filter_status
368                         (sc, telnet_app_id, PORT_MONITOR_SESSION, policy_id, 1);
369                 }
370 #endif
371             }
372         }
373     }
374     else if (strcasecmp(pcToken, TELNET) == 0)
375     {
376         iRet = ProcessTelnetConf(pPolicyConfig, ErrorString, iErrStrLen);
377         enableFtpTelnetPortStreamServices( sc, &pPolicyConfig->telnet_config->proto_ports, NULL,
378                                            SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
379     }
380     else if (strcasecmp(pcToken, FTP) == 0)
381     {
382         pcToken = NextToken(CONF_SEPARATORS);
383 
384         if ( !pcToken )
385         {
386             DynamicPreprocessorFatalMessage(
387                 "%s(%d) Missing ftp_telnet ftp keyword.\n",
388                 *(_dpd.config_file), *(_dpd.config_line));
389         }
390         else if (strcasecmp(pcToken, SERVER) == 0)
391         {
392             iRet = ProcessFTPServerConf(sc, pPolicyConfig, ErrorString, iErrStrLen);
393         }
394         else if (strcasecmp(pcToken, CLIENT) == 0)
395         {
396             iRet = ProcessFTPClientConf(sc, pPolicyConfig, ErrorString, iErrStrLen);
397         }
398         else
399         {
400             DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet ftp keyword.\n",
401                                             *(_dpd.config_file), *(_dpd.config_line));
402         }
403     }
404     else
405     {
406         DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet keyword.\n",
407                                         *(_dpd.config_file), *(_dpd.config_line));
408     }
409 
410     if (iRet)
411     {
412         if(iRet > 0)
413         {
414             /*
415              * Non-fatal Error
416              */
417             if(*ErrorString)
418             {
419                 _dpd.errMsg("WARNING: %s(%d) => %s\n",
420                             *(_dpd.config_file), *(_dpd.config_line), ErrorString);
421             }
422         }
423         else
424         {
425             /*
426              * Fatal Error, log error and exit.
427              */
428             if(*ErrorString)
429             {
430                 DynamicPreprocessorFatalMessage("%s(%d) => %s\n",
431                                                 *(_dpd.config_file), *(_dpd.config_line), ErrorString);
432             }
433             else
434             {
435                 /*
436                  * Check if ErrorString is undefined.
437                  */
438                 if(iRet == -2)
439                 {
440                     DynamicPreprocessorFatalMessage("%s(%d) => ErrorString is undefined.\n",
441                                                     *(_dpd.config_file), *(_dpd.config_line));
442                 }
443                 else
444                 {
445                     DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n",
446                                                     *(_dpd.config_file), *(_dpd.config_line));
447                 }
448             }
449         }
450     }
451 }
452 
453 /*
454  * Function: SetupFTPTelnet()
455  *
456  * Purpose: This function initializes FTPTelnet as a Snort preprocessor.
457  *
458  *          It registers the preprocessor keyword for use in the snort.conf
459  *          and sets up the initialization module for the preprocessor, in
460  *          case it is configured.
461  *
462  *          This function must be called in InitPreprocessors() in plugbase.c
463  *          in order to be recognized by Snort.
464  *
465  * Arguments: None
466  *
467  * Returns: None
468  *
469  */
SetupFTPTelnet(void)470 void SetupFTPTelnet(void)
471 {
472 #ifndef SNORT_RELOAD
473     _dpd.registerPreproc(GLOBAL_KEYWORD, FTPTelnetInit);
474     _dpd.registerPreproc(PROTOCOL_KEYWORD, FTPTelnetInit);
475 #else
476     _dpd.registerPreproc(GLOBAL_KEYWORD, FTPTelnetInit, FtpTelnetReloadGlobal,
477                          FtpTelnetReloadVerify, FtpTelnetReloadSwap,
478                          FtpTelnetReloadSwapFree);
479     _dpd.registerPreproc(PROTOCOL_KEYWORD, FTPTelnetInit,
480                          FtpTelnetReload, NULL, NULL, NULL);
481 #endif
482 
483     DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "Preprocessor: FTPTelnet is "
484                 "setup . . .\n"););
485 #ifdef DUMP_BUFFER
486     _dpd.registerBufferTracer(getFTPTelnetBuffers, FTPTELNET_BUFFER_DUMP_FUNC);
487 #endif
488     _dpd.registerMemoryStatsFunc(PP_FTPTELNET, ftptelnet_print_mem_stats);
489 }
490 
FTPTelnetReset(int signal,void * data)491 static void FTPTelnetReset(int signal, void *data)
492 {
493     return;
494 }
495 
FTPTelnetResetStats(int signal,void * data)496 static void FTPTelnetResetStats(int signal, void *data)
497 {
498     return;
499 }
500 
FTPTelnetStats(int exiting)501 static void FTPTelnetStats(int exiting)
502 {
503     _dpd.logMsg("FTPTelnet Preprocessor Statistics\n");
504     _dpd.logMsg("  Current active FTP sessions                   : " STDu64 "\n",
505                 ftp_telnet_stats.ftp_sessions);
506     _dpd.logMsg("  Max concurrent FTP sessions                   : " STDu64 "\n",
507                 ftp_telnet_stats.max_ftp_sessions);
508     _dpd.logMsg("  Total FTP Data sessions                       : " STDu64 "\n",
509                 ftp_telnet_stats.ftp_data_sessions);
510     _dpd.logMsg("  Max concurrent FTP Data sessions              : " STDu64 "\n",
511                 ftp_telnet_stats.max_ftp_data_sessions);
512     _dpd.logMsg("  Current active Telnet sessions                : " STDu64 "\n",
513                 ftp_telnet_stats.telnet_sessions);
514     _dpd.logMsg("  Max concurrent Telnet sessions                : " STDu64 "\n",
515                 ftp_telnet_stats.max_telnet_sessions);
516     _dpd.logMsg("  Current ftp_telnet session non-mempool memory : " STDu64 "\n",
517                 ftp_telnet_stats.heap_memory);
518 }
519 
ftptelnet_print_mem_stats(FILE * fd,char * buffer,PreprocMemInfo * meminfo)520 int ftptelnet_print_mem_stats(FILE *fd, char* buffer, PreprocMemInfo *meminfo)
521 {
522     time_t curr_time = time(NULL);
523     int len = 0;
524     size_t total_heap_memory = meminfo[PP_MEM_CATEGORY_SESSION].used_memory
525                               + meminfo[PP_MEM_CATEGORY_CONFIG].used_memory;
526     if (fd)
527     {
528         len = fprintf(fd, ","STDu64","STDu64","STDu64""
529                        ","STDu64","STDu64","STDu64""
530                        ",%lu,%u,%u,%lu,%u,%u,%lu"
531                        , ftp_telnet_stats.ftp_sessions
532                        , ftp_telnet_stats.max_ftp_sessions
533                        , ftp_telnet_stats.ftp_data_sessions
534                        , ftp_telnet_stats.max_ftp_data_sessions
535                        , ftp_telnet_stats.telnet_sessions
536                        , ftp_telnet_stats.max_telnet_sessions
537                        , meminfo[PP_MEM_CATEGORY_SESSION].used_memory
538                        , meminfo[PP_MEM_CATEGORY_SESSION].num_of_alloc
539                        , meminfo[PP_MEM_CATEGORY_SESSION].num_of_free
540                        , meminfo[PP_MEM_CATEGORY_CONFIG].used_memory
541                        , meminfo[PP_MEM_CATEGORY_CONFIG].num_of_alloc
542                        , meminfo[PP_MEM_CATEGORY_CONFIG].num_of_free
543                        , total_heap_memory);
544        return len;
545     }
546     if (buffer)
547     {
548         len = snprintf(buffer, CS_STATS_BUF_SIZE,
549                        "\n\nMemory Statistics for FTPTelnet at: %s\n"
550                        "FTPTelnet Preprocessor Statistics:\n"
551                        "       Current active FTP sessions :  "STDu64"\n"
552                        "       Max concurrent FTP sessions :  "STDu64"\n"
553                        "           Total FTP Data sessions :  "STDu64"\n"
554                        "  Max concurrent FTP Data sessions :  "STDu64"\n"
555                        "    Current active Telnet sessions :  "STDu64"\n"
556                        "    Max concurrent Telnet sessions :  "STDu64"\n"
557                        , ctime(&curr_time)
558                        , ftp_telnet_stats.ftp_sessions
559                        , ftp_telnet_stats.max_ftp_sessions
560                        , ftp_telnet_stats.ftp_data_sessions
561                        , ftp_telnet_stats.max_ftp_data_sessions
562                        , ftp_telnet_stats.telnet_sessions
563                        , ftp_telnet_stats.max_telnet_sessions);
564     }
565     else
566     {
567         _dpd.logMsg("\n");
568         _dpd.logMsg("Memory Statistics of FTPTelnet at: %s\n",
569                     ctime(&curr_time));
570         _dpd.logMsg("       Current active FTP sessions :    "STDu64"\n",
571                     ftp_telnet_stats.ftp_sessions);
572         _dpd.logMsg("       Max concurrent FTP sessions :    "STDu64"\n",
573                     ftp_telnet_stats.max_ftp_sessions);
574         _dpd.logMsg("           Total FTP Data sessions :    "STDu64"\n",
575                     ftp_telnet_stats.ftp_data_sessions);
576         _dpd.logMsg("  Max concurrent FTP Data sessions :    "STDu64"\n",
577                     ftp_telnet_stats.max_ftp_data_sessions);
578         _dpd.logMsg("    Current active Telnet sessions :    "STDu64"\n",
579                     ftp_telnet_stats.telnet_sessions);
580         _dpd.logMsg("    Max concurrent Telnet sessions :    "STDu64"\n",
581                     ftp_telnet_stats.max_telnet_sessions);
582     }
583     return len;
584 }
585 
586 #ifdef SNORT_RELOAD
_FtpTelnetReload(struct _SnortConfig * sc,tSfPolicyUserContextId ftp_telnet_swap_config,char * args)587 static void _FtpTelnetReload(struct _SnortConfig *sc, tSfPolicyUserContextId ftp_telnet_swap_config, char *args)
588 {
589     char  *pcToken;
590     char ErrorString[ERRSTRLEN];
591     int iErrStrLen = ERRSTRLEN;
592     int iRet = 0;
593     tSfPolicyId policy_id = _dpd.getParserPolicy(sc);
594     FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL;
595 
596     ErrorString[0] = '\0';
597 
598     if ((args == NULL) || (strlen(args) == 0))
599     {
600         DynamicPreprocessorFatalMessage("%s(%d) No arguments to FtpTelnet "
601                 "configuration.\n", *_dpd.config_file, *_dpd.config_line);
602     }
603 
604     /* Find out what is getting configured */
605     maxToken = args + strlen(args);
606     pcToken = mystrtok(args, CONF_SEPARATORS);
607     if (pcToken == NULL)
608     {
609         DynamicPreprocessorFatalMessage("%s(%d)mystrtok returned NULL when it "
610                                         "should not.", __FILE__, __LINE__);
611     }
612 
613     /*
614      * Global Configuration Processing
615      * We only process the global configuration once, but always check for
616      * user mistakes, like configuring more than once.  That's why we
617      * still check for the global token even if it's been checked.
618      */
619     sfPolicyUserPolicySet (ftp_telnet_swap_config, policy_id);
620     pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_swap_config);
621 
622     if (pPolicyConfig == NULL)
623     {
624         if (strcasecmp(pcToken, GLOBAL) != 0)
625         {
626             DynamicPreprocessorFatalMessage("%s(%d) Must configure the "
627                 "ftptelnet global configuration first.\n",
628                 *_dpd.config_file, *_dpd.config_line);
629         }
630 
631         pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)_dpd.snortAlloc(1,
632                                                   sizeof(FTPTELNET_GLOBAL_CONF),
633                                                   PP_FTPTELNET,
634                                                   PP_MEM_CATEGORY_CONFIG);
635 
636         if (pPolicyConfig == NULL)
637         {
638             DynamicPreprocessorFatalMessage("No memory to allocate "
639                                             "FTP/Telnet configuration.\n");
640         }
641 
642         sfPolicyUserDataSetCurrent(ftp_telnet_swap_config, pPolicyConfig);
643 
644         iRet = FtpTelnetInitGlobalConfig(pPolicyConfig,
645                                          ErrorString, iErrStrLen);
646 
647         if (iRet == 0)
648         {
649             iRet = ProcessFTPGlobalConf(pPolicyConfig,
650                                      ErrorString, iErrStrLen);
651 
652             if (iRet == 0)
653             {
654                 PrintFTPGlobalConf(pPolicyConfig);
655 
656                 _dpd.preprocOptRegister(sc, "ftp.bounce", &FTPPBounceInit, &FTPPBounceEval,
657                         NULL, NULL, NULL, NULL, NULL);
658             }
659         }
660     }
661     else if (strcasecmp(pcToken, TELNET) == 0)
662     {
663         iRet = ProcessTelnetConf(pPolicyConfig, ErrorString, iErrStrLen);
664         enableFtpTelnetPortStreamServices( sc, &pPolicyConfig->telnet_config->proto_ports, NULL,
665                                            SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
666     }
667     else if (strcasecmp(pcToken, FTP) == 0)
668     {
669         pcToken = NextToken(CONF_SEPARATORS);
670 
671         if ( !pcToken )
672         {
673             DynamicPreprocessorFatalMessage(
674                 "%s(%d) Missing ftp_telnet ftp keyword.\n",
675                 *(_dpd.config_file), *(_dpd.config_line));
676         }
677         else if (strcasecmp(pcToken, SERVER) == 0)
678         {
679             iRet = ProcessFTPServerConf(sc, pPolicyConfig, ErrorString, iErrStrLen);
680         }
681         else if (strcasecmp(pcToken, CLIENT) == 0)
682         {
683             iRet = ProcessFTPClientConf(sc, pPolicyConfig, ErrorString, iErrStrLen);
684         }
685         else
686         {
687             DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet ftp keyword.\n",
688                                             *(_dpd.config_file), *(_dpd.config_line));
689         }
690     }
691     else
692     {
693         DynamicPreprocessorFatalMessage("%s(%d) Invalid ftp_telnet keyword.\n",
694                                         *(_dpd.config_file), *(_dpd.config_line));
695     }
696 
697     if (iRet)
698     {
699         if(iRet > 0)
700         {
701             /*
702              * Non-fatal Error
703              */
704             if(*ErrorString)
705             {
706                 _dpd.errMsg("WARNING: %s(%d) => %s\n",
707                             *(_dpd.config_file), *(_dpd.config_line), ErrorString);
708             }
709         }
710         else
711         {
712             /*
713              * Fatal Error, log error and exit.
714              */
715             if(*ErrorString)
716             {
717                 DynamicPreprocessorFatalMessage("%s(%d) => %s\n",
718                                                 *(_dpd.config_file), *(_dpd.config_line), ErrorString);
719             }
720             else
721             {
722                 /*
723                  * Check if ErrorString is undefined.
724                  */
725                 if(iRet == -2)
726                 {
727                     DynamicPreprocessorFatalMessage("%s(%d) => ErrorString is undefined.\n",
728                                                     *(_dpd.config_file), *(_dpd.config_line));
729                 }
730                 else
731                 {
732                     DynamicPreprocessorFatalMessage("%s(%d) => Undefined Error.\n",
733                                                     *(_dpd.config_file), *(_dpd.config_line));
734                 }
735             }
736         }
737     }
738 }
739 
FtpTelnetReloadGlobal(struct _SnortConfig * sc,char * args,void ** new_config)740 static void FtpTelnetReloadGlobal(struct _SnortConfig *sc, char *args, void **new_config)
741 {
742     tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)*new_config;
743 
744     if (ftp_telnet_swap_config == NULL)
745     {
746         //create a context
747         ftp_telnet_swap_config = sfPolicyConfigCreate();
748 
749         if (ftp_telnet_swap_config == NULL)
750         {
751             DynamicPreprocessorFatalMessage("No memory to allocate "
752                                             "FTP/Telnet swap_configuration.\n");
753         }
754         *new_config = (void *)ftp_telnet_swap_config;
755     }
756     _FtpTelnetReload(sc, ftp_telnet_swap_config, args);
757 }
758 
FtpTelnetReload(struct _SnortConfig * sc,char * args,void ** new_config)759 static void FtpTelnetReload(struct _SnortConfig *sc, char *args, void **new_config)
760 {
761     tSfPolicyUserContextId ftp_telnet_swap_config;
762     ftp_telnet_swap_config = (tSfPolicyUserContextId)_dpd.getRelatedReloadData(sc, GLOBAL_KEYWORD);
763     _FtpTelnetReload(sc, ftp_telnet_swap_config, args);
764 }
765 
FtpTelnetReloadVerifyPolicy(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)766 static int FtpTelnetReloadVerifyPolicy(
767         struct _SnortConfig *sc,
768         tSfPolicyUserContextId config,
769         tSfPolicyId policyId,
770         void* pData
771         )
772 {
773     return FTPTelnetCheckConfigs( sc, pData, policyId );
774 }
775 
FtpTelnetReloadVerify(struct _SnortConfig * sc,void * new_config)776 static int FtpTelnetReloadVerify(struct _SnortConfig *sc, void *new_config)
777 {
778     tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)new_config;
779 
780     if (ftp_telnet_swap_config == NULL)
781         return 0;
782 
783     if (sfPolicyUserDataIterate (sc, ftp_telnet_swap_config, FtpTelnetReloadVerifyPolicy))
784         return -1;
785 
786     return 0;
787 }
788 
FtpTelnetReloadSwapPolicy(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)789 static int FtpTelnetReloadSwapPolicy(
790         struct _SnortConfig *sc,
791         tSfPolicyUserContextId config,
792         tSfPolicyId policyId,
793         void* pData
794         )
795 {
796     FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData;
797 
798     //do any housekeeping before freeing FTPTELNET_GLOBAL_CONF
799     if (pPolicyConfig->ref_count == 0)
800     {
801         sfPolicyUserDataClear (config, policyId);
802         FTPTelnetFreeConfig(pPolicyConfig);
803     }
804 
805     return 0;
806 }
807 
FtpTelnetReloadSwap(struct _SnortConfig * sc,void * new_config)808 static void * FtpTelnetReloadSwap(struct _SnortConfig *sc, void *new_config)
809 {
810     tSfPolicyUserContextId ftp_telnet_swap_config = (tSfPolicyUserContextId)new_config;
811     tSfPolicyUserContextId old_config = ftp_telnet_config;
812 
813     if (ftp_telnet_swap_config == NULL)
814         return NULL;
815 
816     ftp_telnet_config = ftp_telnet_swap_config;
817 
818     sfPolicyUserDataIterate (sc, old_config, FtpTelnetReloadSwapPolicy);
819 
820     if (sfPolicyUserPolicyGetActive(old_config) == 0)
821         return (void *)old_config;
822 
823     return NULL;
824 }
825 
FtpTelnetReloadSwapFree(void * data)826 static void FtpTelnetReloadSwapFree(void *data)
827 {
828     if (data == NULL)
829         return;
830 
831     FTPTelnetFreeConfigs((tSfPolicyUserContextId)data);
832 }
833 
834 #endif
835