1 /*
2 * snort_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 wraps the FTPTelnet functionality for Snort
29 * and starts the Normalization & Protocol checks.
30 *
31 * The file takes a Packet structure from the Snort IDS to start the
32 * FTP/Telnet Normalization & Protocol checks. It also uses the Stream
33 * Interface Module which is also Snort-centric. Mainly, just a wrapper
34 * to FTP/Telnet functionality, but a key part to starting the basic flow.
35 *
36 * The main bulk of this file is taken up with user configuration and
37 * parsing. The reason this is so large is because FTPTelnet takes
38 * very detailed configuration parameters for each specified FTP client,
39 * to provide detailed control over an internal network and robust control
40 * of the external network.
41 *
42 * The main functions of note are:
43 * - FTPTelnetSnortConf() the configuration portion
44 * - SnortFTPTelnet() the actual normalization & inspection
45 * - LogEvents() where we log the FTPTelnet events
46 *
47 * NOTES:
48 * - 16.09.04: Initial Development. SAS
49 *
50 */
51
52 #define _GNU_SOURCE
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 #ifdef HAVE_STRINGS_H
59 #include <strings.h>
60 #endif
61
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
65 #include <sys/types.h>
66 #include <errno.h>
67 #include "sf_ip.h"
68
69 #ifndef WIN32
70 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <ctype.h>
74 #endif
75
76 #define BUF_SIZE 1024
77
78 #include "sf_types.h"
79 #include "snort_debug.h"
80 #include "ftpp_return_codes.h"
81 #include "ftpp_ui_config.h"
82 #include "ftpp_ui_client_lookup.h"
83 #include "ftpp_ui_server_lookup.h"
84 #include "ftp_cmd_lookup.h"
85 #include "ftp_bounce_lookup.h"
86 #include "ftpp_si.h"
87 #include "ftpp_eo_log.h"
88 #include "pp_telnet.h"
89 #include "pp_ftp.h"
90 #include "snort_ftptelnet.h"
91 #include "sfPolicy.h"
92 #include "sfPolicyUserData.h"
93 #include "stream_api.h"
94 #include "profiler.h"
95 #include "sf_snort_plugin_api.h"
96 #include "Unified2_common.h"
97 #include "ssl_include.h"
98 #include <daq_common.h>
99 #include "memory_stats.h"
100
101 #ifdef DUMP_BUFFER
102 #include "ftptelnet_buffer_dump.h"
103 #endif
104
105 #ifdef PERF_PROFILING
106 extern PreprocStats ftpPerfStats;
107 extern PreprocStats telnetPerfStats;
108 PreprocStats ftppDetectPerfStats;
109 int ftppDetectCalled = 0;
110 #endif
111
112 #ifdef TARGET_BASED
113 unsigned s_ftpdata_eof_cb_id = 0;
114 unsigned s_ftpdata_flush_cb_id = 0;
115 #endif
116
117 extern tSfPolicyUserContextId ftp_telnet_config;
118
119 /*
120 * GLOBAL subkeyword values
121 */
122 #define ENCRYPTED_TRAFFIC "encrypted_traffic"
123 #define CHECK_ENCRYPTED "check_encrypted"
124 #define INSPECT_TYPE "inspection_type"
125 #define INSPECT_TYPE_STATELESS "stateless"
126 #define INSPECT_TYPE_STATEFUL "stateful"
127 /*
128 * Protocol subkeywords.
129 */
130 #define PORTS "ports"
131
132 /*
133 * Telnet subkeywords.
134 */
135 #define AYT_THRESHOLD "ayt_attack_thresh"
136 #define NORMALIZE "normalize"
137 #define DETECT_ANOMALIES "detect_anomalies"
138
139 /*
140 * FTP SERVER subkeywords.
141 */
142 #define FTP_CMDS "ftp_cmds"
143 #define PRINT_CMDS "print_cmds"
144 #define MAX_PARAM_LEN "def_max_param_len"
145 #define ALT_PARAM_LEN "alt_max_param_len"
146 #define CMD_VALIDITY "cmd_validity"
147 #define STRING_FORMAT "chk_str_fmt"
148 #define TELNET_CMDS "telnet_cmds"
149 #define IGNORE_TELNET_CMDS "ignore_telnet_erase_cmds"
150 #define DATA_CHAN_CMD "data_chan_cmds"
151 #define DATA_XFER_CMD "data_xfer_cmds"
152 #define DATA_REST_CMD "data_rest_cmds"
153 #define FILE_PUT_CMD "file_put_cmds"
154 #define FILE_GET_CMD "file_get_cmds"
155 #define DATA_CHAN "data_chan"
156 #define LOGIN_CMD "login_cmds"
157 #define ENCR_CMD "encr_cmds"
158 #define DIR_CMD "dir_cmds"
159 #define IGNORE_DATA_CHAN "ignore_data_chan"
160
161 /*
162 * FTP CLIENT subkeywords
163 */
164 #define BOUNCE "bounce"
165 #define ALLOW_BOUNCE "bounce_to"
166 #define MAX_RESP_LEN "max_resp_len"
167
168 /*
169 * Data type keywords
170 */
171 #define START_CMD_FORMAT "<"
172 #define END_CMD_FORMAT ">"
173 #define F_INT "int"
174 #define F_NUMBER "number"
175 #define F_CHAR "char"
176 #define F_DATE "date"
177 #define F_LITERAL "'"
178 #define F_STRING "string"
179 #define F_STRING_FMT "formated_string"
180 #define F_HOST_PORT "host_port"
181 #define F_LONG_HOST_PORT "long_host_port"
182 #define F_EXTD_HOST_PORT "extd_host_port"
183
184 /*
185 * Optional parameter delimiters
186 */
187 #define START_OPT_FMT "["
188 #define END_OPT_FMT "]"
189 #define START_CHOICE_FMT "{"
190 #define END_CHOICE_FMT "}"
191 #define OR_FMT "|"
192
193
194 /*
195 * The cmd_validity keyword can be used with the format keyword to
196 * restrict data types. The interpretation is specific to the data
197 * type. 'format' is only supported with date & char data types.
198 *
199 * A few examples:
200 *
201 * 1. Will perform validity checking of an FTP Mode command to
202 * check for one of the characters A, S, B, or C.
203 *
204 * cmd_validity MODE char ASBC
205 *
206 *
207 * 2. Will perform validity checking of an FTP MDTM command to
208 * check for an optional date argument following the format
209 * specified. The date would uses the YYYYMMDDHHmmss+TZ format.
210 *
211 * cmd_validity MDTM [ date nnnnnnnnnnnnnn[.n[n[n]]] ] string
212 *
213 *
214 * 3. Will perform validity checking of an FTP ALLO command to
215 * check for an integer, then optionally, the letter R and another
216 * integer.
217 *
218 * cmd_validity ALLO int [ char R int ]
219 */
220
221 /*
222 * The def_max_param_len & alt_max_param_len keywords can be used to
223 * restrict parameter length for one or more commands. The space
224 * separated list of commands is enclosed in {}s.
225 *
226 * A few examples:
227 *
228 * 1. Restricts all command parameters to 100 characters
229 *
230 * def_max_param_len 100
231 *
232 * 2. Overrides CWD pathname to 256 characters
233 *
234 * alt_max_param_len 256 { CWD }
235 *
236 * 3. Overrides PWD & SYST to no parameters
237 *
238 * alt_max_param_len 0 { PWD SYST }
239 *
240 */
241
242 /*
243 * Alert subkeywords
244 */
245 #define BOOL_YES "yes"
246 #define BOOL_NO "no"
247
248 /*
249 ** IP Address list delimiters
250 */
251 #define START_IPADDR_LIST "{"
252 #define END_IPADDR_LIST "}"
253
254 /*
255 * Port list delimiters
256 */
257 #define START_PORT_LIST "{"
258 #define END_PORT_LIST "}"
259
260 /*
261 * Keyword for the default client/server configuration
262 */
263 #define DEFAULT "default"
264
265 /*
266 * The default FTP server configuration for FTP command validation.
267 * Most of this comes from RFC 959, with additional commands being
268 * drawn from other RFCs/Internet Drafts that are in use.
269 *
270 * Any of the below can be overridden in snort.conf.
271 *
272 * This is here to eliminate most of it from snort.conf to
273 * avoid an ugly configuration file. The default_max_param_len
274 * is somewhat arbitrary, but is taken from the majority of
275 * the snort FTP rules that limit parameter size to 100
276 * characters, as of 18 Sep 2004.
277 *
278 * The data_chan_cmds, data_xfer_cmds are used to track open
279 * data channel connections.
280 *
281 * The login_cmds and dir_cmds are used to track state of username
282 * and current directory.
283 *
284 * The file_put_cmds and file_get_cmds are used to track file transfers
285 * over open data channel connections.
286 */
287 /* DEFAULT_FTP_CONF_* deliberately break the default conf into
288 * chunks with lengths < 509 to keep ISO C89 compilers happy
289 */
290 static const char* DEFAULT_FTP_CONF[] = {
291 "hardcoded_config "
292 "def_max_param_len 100 "
293
294 "ftp_cmds { USER PASS ACCT CWD CDUP SMNT QUIT REIN TYPE STRU"
295 " MODE RETR STOR STOU APPE ALLO REST RNFR RNTO ABOR"
296 " DELE RMD MKD PWD LIST NLST SITE SYST STAT HELP NOOP } "
297 "ftp_cmds { AUTH ADAT PROT PBSZ CONF ENC } "
298 "ftp_cmds { PORT PASV LPRT LPSV EPRT EPSV } "
299 "ftp_cmds { FEAT OPTS } "
300 "ftp_cmds { MDTM REST SIZE MLST MLSD } "
301
302 "alt_max_param_len 0 { CDUP QUIT REIN PASV STOU ABOR PWD SYST NOOP } ",
303
304 "cmd_validity MODE < char SBC > "
305 "cmd_validity STRU < char FRPO [ string ] > "
306 "cmd_validity ALLO < int [ char R int ] > "
307 "cmd_validity TYPE < { char AE [ char NTC ] | char I | char L [ number ] } > "
308 "cmd_validity PORT < host_port > "
309 "cmd_validity LPRT < long_host_port > "
310 "cmd_validity EPRT < extd_host_port > "
311 "cmd_validity EPSV < [ { '1' | '2' | 'ALL' } ] > ",
312
313 "data_chan_cmds { PORT PASV LPRT LPSV EPRT EPSV } "
314 "data_xfer_cmds { RETR STOR STOU APPE LIST NLST } "
315 "data_rest_cmds { REST } "
316 "file_put_cmds { STOR STOU } "
317 "file_get_cmds { RETR } "
318 "login_cmds { USER PASS } "
319 "dir_cmds { CWD 250 CDUP 250 PWD 257 } "
320 "encr_cmds { AUTH } "
321 };
322
323 #define CONF_CHUNKS (sizeof(DEFAULT_FTP_CONF)/sizeof(DEFAULT_FTP_CONF[0]))
324
325 static uint8_t ftp_paf_id = 0;
326
DefaultConf(size_t * pn)327 static char* DefaultConf (size_t* pn) {
328 unsigned i;
329 size_t sz = 1, ns = 0;
330 char* str = NULL;
331
332 for ( i = 0; i < CONF_CHUNKS; i++ )
333 sz += strlen(DEFAULT_FTP_CONF[i]);
334
335 str = _dpd.snortAlloc(1, sz, PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
336
337 if ( !str )
338 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
339 *(_dpd.config_file), *(_dpd.config_line));
340
341 for ( i = 0; i < CONF_CHUNKS; i++ )
342 ns += snprintf(str+ns, sz-ns, "%s", DEFAULT_FTP_CONF[i]);
343
344 *pn = sz;
345 return str;
346 }
347
348 static int printedFTPHeader = 0;
349 static int _checkServerConfig(struct _SnortConfig *, void *pData);
350
351 char *maxToken = NULL;
352 static tSfPolicyId ftp_current_policy = 0;
353
354 static void _addPortsToStream(struct _SnortConfig *, char *, tSfPolicyId, int);
355 static int _addFtpServerConfPortsToStream(struct _SnortConfig *, void *);
356
357 static void _FTPTelnetAddPortsOfInterest(struct _SnortConfig *, FTPTELNET_GLOBAL_CONF *, tSfPolicyId);
358 #ifdef TARGET_BASED
359 static void _FTPTelnetAddService(struct _SnortConfig *, int16_t, tSfPolicyId);
360 #endif
361 void FTP_Set_flow_id( void *app_data, uint32_t fid );
362 void FTPData_Set_flow_id( void *app_data, uint32_t fid );
363
mystrtok(char * s,const char * delim)364 char* mystrtok (char* s, const char* delim)
365 {
366 static char* last = NULL;
367 if ( s || last )
368 last = strtok(s, delim);
369 return last;
370 }
371
NextToken(char * delimiters)372 char *NextToken(char *delimiters)
373 {
374 char *retTok = mystrtok(NULL, delimiters);
375 if (retTok > maxToken)
376 return NULL;
377
378 return retTok;
379 }
380
381 /*
382 * Function: ProcessConfOpt(FTPTELNET_CONF_OPT *ConfOpt,
383 * char *Option,
384 * char *ErrorString, int ErrStrLen)
385 *
386 * Purpose: Set the CONF_OPT on and alert fields.
387 *
388 * We check to make sure of valid parameters and then set
389 * the appropriate fields.
390 *
391 * Arguments: ConfOpt => pointer to the configuration option
392 * Option => character pointer to the option being configured
393 * ErrorString => error string buffer
394 * ErrStrLen => the length of the error string buffer
395 *
396 * Returns: int => an error code integer (0 = success,
397 * >0 = non-fatal error, <0 = fatal error)
398 *
399 */
ProcessConfOpt(FTPTELNET_CONF_OPT * ConfOpt,char * Option,char * ErrorString,int ErrStrLen)400 static int ProcessConfOpt(FTPTELNET_CONF_OPT *ConfOpt, char *Option,
401 char *ErrorString, int ErrStrLen)
402 {
403 char *pcToken;
404
405 pcToken = NextToken(CONF_SEPARATORS);
406 if(pcToken == NULL)
407 {
408 snprintf(ErrorString, ErrStrLen,
409 "No argument to token '%s'.", Option);
410
411 return FTPP_FATAL_ERR;
412 }
413
414 /*
415 * Check for the alert value
416 */
417 if(!strcmp(BOOL_YES, pcToken))
418 {
419 ConfOpt->alert = 1;
420 }
421 else if(!strcmp(BOOL_NO, pcToken))
422 {
423 ConfOpt->alert = 0;
424 }
425 else
426 {
427 snprintf(ErrorString, ErrStrLen,
428 "Invalid argument to token '%s'.", Option);
429
430 return FTPP_FATAL_ERR;
431 }
432
433 ConfOpt->on = 1;
434
435 return FTPP_SUCCESS;
436 }
437
438 /*
439 * Function: PrintConfOpt(FTPTELNET_CONF_OPT *ConfOpt,
440 * char *Option)
441 *
442 * Purpose: Prints the CONF_OPT and alert fields.
443 *
444 * Arguments: ConfOpt => pointer to the configuration option
445 * Option => character pointer to the option being configured
446 *
447 * Returns: int => an error code integer (0 = success,
448 * >0 = non-fatal error, <0 = fatal error)
449 *
450 */
PrintConfOpt(FTPTELNET_CONF_OPT * ConfOpt,char * Option)451 static int PrintConfOpt(FTPTELNET_CONF_OPT *ConfOpt, char *Option)
452 {
453 if(!ConfOpt || !Option)
454 {
455 return FTPP_INVALID_ARG;
456 }
457
458 if(ConfOpt->on)
459 {
460 _dpd.logMsg(" %s: YES alert: %s\n", Option,
461 ConfOpt->alert ? "YES" : "NO");
462 }
463 else
464 {
465 _dpd.logMsg(" %s: OFF\n", Option);
466 }
467
468 return FTPP_SUCCESS;
469 }
470
471 /*
472 * Function: ProcessInspectType(FTPTELNET_CONF_OPT *ConfOpt,
473 * char *ErrorString, int ErrStrLen)
474 *
475 * Purpose: Process the type of inspection.
476 * This sets the type of inspection for FTPTelnet to do.
477 *
478 * Arguments: GlobalConf => pointer to the global configuration
479 * ErrorString => error string buffer
480 * ErrStrLen => the length of the error string buffer
481 *
482 * Returns: int => an error code integer (0 = success,
483 * >0 = non-fatal error, <0 = fatal error)
484 *
485 */
ProcessInspectType(FTPTELNET_GLOBAL_CONF * GlobalConf,char * ErrorString,int ErrStrLen)486 static int ProcessInspectType(FTPTELNET_GLOBAL_CONF *GlobalConf,
487 char *ErrorString, int ErrStrLen)
488 {
489 char *pcToken;
490
491 pcToken = NextToken(CONF_SEPARATORS);
492 if(pcToken == NULL)
493 {
494 snprintf(ErrorString, ErrStrLen,
495 "No argument to token '%s'.", INSPECT_TYPE);
496
497 return FTPP_FATAL_ERR;
498 }
499
500 if(!strcmp(INSPECT_TYPE_STATEFUL, pcToken))
501 {
502 GlobalConf->inspection_type = FTPP_UI_CONFIG_STATEFUL;
503 }
504 else if(!strcmp(INSPECT_TYPE_STATELESS, pcToken))
505 {
506 GlobalConf->inspection_type = FTPP_UI_CONFIG_STATELESS;
507 }
508 else
509 {
510 snprintf(ErrorString, ErrStrLen,
511 "Invalid argument to token '%s'. Must be either "
512 "'%s' or '%s'.", INSPECT_TYPE, INSPECT_TYPE_STATEFUL,
513 INSPECT_TYPE_STATELESS);
514
515 return FTPP_FATAL_ERR;
516 }
517
518 return FTPP_SUCCESS;
519 }
520
521 /*
522 * Function: ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf,
523 * char *ErrorString, int ErrStrLen)
524 *
525 * Purpose: This is where we process the global configuration for FTPTelnet.
526 *
527 * We set the values of the global configuraiton here. Any errors
528 * that are encountered are specified in the error string and the
529 * type of error is returned through the return code, i.e. fatal,
530 * non-fatal.
531 *
532 * The configuration options that are dealt with here are:
533 * - inspection_type
534 * Indicate whether to operate in stateful stateless mode
535 * - encrypted_traffic
536 * Detect and alert on encrypted sessions
537 * - check_after_encrypted
538 * Instructs the preprocessor to continue checking a data stream
539 * after it is encrypted, looking for an eventual
540 * non-ecrypted data.
541 *
542 * Arguments: GlobalConf => pointer to the global configuration
543 * ErrorString => error string buffer
544 * ErrStrLen => the length of the error string buffer
545 *
546 * Returns: int => an error code integer (0 = success,
547 * >0 = non-fatal error, <0 = fatal error)
548 *
549 */
ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF * GlobalConf,char * ErrorString,int ErrStrLen)550 int ProcessFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf,
551 char *ErrorString, int ErrStrLen)
552 {
553 FTPTELNET_CONF_OPT *ConfOpt;
554 int iRet = 0;
555 char *pcToken;
556 int iTokens = 0;
557
558 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
559 {
560 /*
561 * Show that we at least got one token
562 */
563 iTokens = 1;
564
565 /*
566 * Search for configuration keywords
567 */
568 if (!strcmp(pcToken, CHECK_ENCRYPTED))
569 {
570 GlobalConf->check_encrypted_data = 1;
571 }
572 else if (!strcmp(pcToken, ENCRYPTED_TRAFFIC))
573 {
574 ConfOpt = &GlobalConf->encrypted;
575 iRet = ProcessConfOpt(ConfOpt, ENCRYPTED_TRAFFIC, ErrorString, ErrStrLen);
576 if (iRet)
577 {
578 return iRet;
579 }
580 }
581 else if(!strcmp(INSPECT_TYPE, pcToken))
582 {
583 iRet = ProcessInspectType(GlobalConf, ErrorString, ErrStrLen);
584 if (iRet)
585 {
586 return iRet;
587 }
588 }
589 else
590 {
591 snprintf(ErrorString, ErrStrLen,
592 "Invalid keyword '%s' for '%s' configuration.",
593 pcToken, GLOBAL);
594
595 return FTPP_FATAL_ERR;
596 }
597 }
598
599 /*
600 * If there are not any tokens to the configuration, then
601 * we let the user know and log the error. return non-fatal
602 * error.
603 */
604 if(!iTokens)
605 {
606 snprintf(ErrorString, ErrStrLen,
607 "No tokens to '%s' configuration.", GLOBAL);
608
609 return FTPP_NONFATAL_ERR;
610 }
611
612 return FTPP_SUCCESS;
613 }
614
615 /*
616 * Function: ProcessPorts(PROTO_CONF *protocol,
617 * char *ErrorString, int ErrStrLen)
618 *
619 * Purpose: Process the port list for the server configuration.
620 * This configuration is a list of valid ports and is ended
621 * by a delimiter.
622 *
623 * Arguments: protocol => pointer to the ports configuration
624 * ErrorString => error string buffer
625 * ErrStrLen => the length of the error string buffer
626 *
627 * Returns: int => an error code integer (0 = success,
628 * >0 = non-fatal error, <0 = fatal error)
629 *
630 */
ProcessPorts(PROTO_CONF * protocol,char * ErrorString,int ErrStrLen)631 static int ProcessPorts(PROTO_CONF *protocol,
632 char *ErrorString, int ErrStrLen)
633 {
634 char *pcToken;
635 char *pcEnd;
636 int iPort;
637 int iEndPorts = 0;
638
639 pcToken = NextToken(CONF_SEPARATORS);
640 if(!pcToken)
641 {
642 snprintf(ErrorString, ErrStrLen,
643 "Invalid port list format.");
644
645 return FTPP_FATAL_ERR;
646 }
647
648 if(strcmp(START_PORT_LIST, pcToken))
649 {
650 snprintf(ErrorString, ErrStrLen,
651 "Must start a port list with the '%s' token.",
652 START_PORT_LIST);
653
654 return FTPP_FATAL_ERR;
655 }
656
657 /* Unset the defaults */
658 for (iPort = 0;iPort<MAXPORTS;iPort++)
659 protocol->ports[iPort] = 0;
660
661 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
662 {
663 if(!strcmp(END_PORT_LIST, pcToken))
664 {
665 iEndPorts = 1;
666 break;
667 }
668
669 iPort = strtol(pcToken, &pcEnd, 10);
670
671 /*
672 * Validity check for port
673 */
674 if(*pcEnd)
675 {
676 snprintf(ErrorString, ErrStrLen,
677 "Invalid port number.");
678
679 return FTPP_FATAL_ERR;
680 }
681
682 if(iPort < 0 || iPort > MAXPORTS-1)
683 {
684 snprintf(ErrorString, ErrStrLen,
685 "Invalid port number. Must be between 0 and "
686 "65535.");
687
688 return FTPP_FATAL_ERR;
689 }
690
691 protocol->ports[iPort] = 1;
692
693 if(protocol->port_count < MAXPORTS)
694 protocol->port_count++;
695 }
696
697 if(!iEndPorts)
698 {
699 snprintf(ErrorString, ErrStrLen,
700 "Must end '%s' configuration with '%s'.",
701 PORTS, END_PORT_LIST);
702
703 return FTPP_FATAL_ERR;
704 }
705
706 return FTPP_SUCCESS;
707 }
708
709 /*
710 * Function: ProcessTelnetAYTThreshold(TELNET_PROTO_CONF *TelnetConf,
711 * char *ErrorString, int ErrStrLen)
712 *
713 * Purpose: Process the 'are you there' threshold configuration
714 * This sets the maximum number of telnet ayt commands that
715 * we will tolerate, before alerting.
716 *
717 * Arguments: TelnetConf => pointer to the telnet configuration
718 * ErrorString => error string buffer
719 * ErrStrLen => the length of the error string buffer
720 *
721 * Returns: int => an error code integer (0 = success,
722 * >0 = non-fatal error, <0 = fatal error)
723 *
724 */
ProcessTelnetAYTThreshold(TELNET_PROTO_CONF * TelnetConf,char * ErrorString,int ErrStrLen)725 static int ProcessTelnetAYTThreshold(TELNET_PROTO_CONF *TelnetConf,
726 char *ErrorString, int ErrStrLen)
727 {
728 char *pcToken;
729 char *pcEnd = NULL;
730
731 pcToken = NextToken(CONF_SEPARATORS);
732 if(pcToken == NULL)
733 {
734 snprintf(ErrorString, ErrStrLen,
735 "No argument to token '%s'.", AYT_THRESHOLD);
736
737 return FTPP_FATAL_ERR;
738 }
739
740 TelnetConf->ayt_threshold = strtol(pcToken, &pcEnd, 10);
741
742 /*
743 * Let's check to see if the entire string was valid.
744 * If there is an address here, then there was an
745 * invalid character in the string.
746 */
747 if(*pcEnd)
748 {
749 snprintf(ErrorString, ErrStrLen,
750 "Invalid argument to token '%s'. Must be a positive "
751 "number.", AYT_THRESHOLD);
752
753 return FTPP_FATAL_ERR;
754 }
755
756 return FTPP_SUCCESS;
757 }
758
759 /*
760 * Function: PrintTelnetConf(TELNET_PROTO_CONF *TelnetConf,
761 * char *Option)
762 *
763 * Purpose: Prints the telnet configuration
764 *
765 * Arguments: TelnetConf => pointer to the telnet configuration
766 *
767 * Returns: int => an error code integer (0 = success,
768 * >0 = non-fatal error, <0 = fatal error)
769 *
770 */
PrintTelnetConf(TELNET_PROTO_CONF * TelnetConf)771 static int PrintTelnetConf(TELNET_PROTO_CONF *TelnetConf)
772 {
773 char buf[BUF_SIZE+1];
774 int iCtr;
775
776 if(!TelnetConf)
777 {
778 return FTPP_INVALID_ARG;
779 }
780
781 _dpd.logMsg(" TELNET CONFIG:\n");
782 memset(buf, 0, BUF_SIZE+1);
783 snprintf(buf, BUF_SIZE, " Ports: ");
784
785 /*
786 * Print out all the applicable ports.
787 */
788 for(iCtr = 0; iCtr < MAXPORTS; iCtr++)
789 {
790 if(TelnetConf->proto_ports.ports[iCtr])
791 {
792 _dpd.printfappend(buf, BUF_SIZE, "%d ", iCtr);
793 }
794 }
795
796 _dpd.logMsg("%s\n", buf);
797
798 _dpd.logMsg(" Are You There Threshold: %d\n",
799 TelnetConf->ayt_threshold);
800 _dpd.logMsg(" Normalize: %s\n", TelnetConf->normalize ? "YES" : "NO");
801 _dpd.logMsg(" Detect Anomalies: %s\n",
802 TelnetConf->detect_anomalies ? "YES" : "NO");
803
804 return FTPP_SUCCESS;
805 }
806
807 /*
808 * Function: ProcessTelnetConf(FTPTELNET_GLOBAL_CONF *GlobalConf,
809 * char *ErrorString, int ErrStrLen)
810 *
811 * Purpose: This is where we process the telnet configuration for FTPTelnet.
812 *
813 * We set the values of the telnet configuraiton here. Any errors
814 * that are encountered are specified in the error string and the
815 * type of error is returned through the return code, i.e. fatal,
816 * non-fatal.
817 *
818 * The configuration options that are dealt with here are:
819 * - ports { x } Ports on which to do telnet checks
820 * - normalize Turns on normalization
821 * - ayt_attack_thresh x Detect consecutive are you there commands
822 *
823 * Arguments: GlobalConf => pointer to the global configuration
824 * ErrorString => error string buffer
825 * ErrStrLen => the length of the error string buffer
826 *
827 * Returns: int => an error code integer (0 = success,
828 * >0 = non-fatal error, <0 = fatal error)
829 *
830 */
ProcessTelnetConf(FTPTELNET_GLOBAL_CONF * GlobalConf,char * ErrorString,int ErrStrLen)831 int ProcessTelnetConf(FTPTELNET_GLOBAL_CONF *GlobalConf,
832 char *ErrorString, int ErrStrLen)
833 {
834 int iRet;
835 char *pcToken;
836 int iTokens = 0;
837
838 if (GlobalConf->telnet_config != NULL)
839 {
840 snprintf(ErrorString, ErrStrLen,
841 "Telnet can only be configured once.\n");
842
843 return FTPP_FATAL_ERR;
844 }
845
846 GlobalConf->telnet_config =
847 (TELNET_PROTO_CONF *)_dpd.snortAlloc(1, sizeof(TELNET_PROTO_CONF),
848 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
849 if (GlobalConf->telnet_config == NULL)
850 {
851 DynamicPreprocessorFatalMessage("Out of memory trying to create "
852 "telnet configuration.\n");
853 }
854
855 /*
856 * Reset the global telnet configuration
857 */
858 if(ftpp_ui_config_reset_telnet_proto(GlobalConf->telnet_config))
859 {
860 snprintf(ErrorString, ErrStrLen,
861 "Cannot reset the FTPTelnet global telnet configuration.");
862
863 return FTPP_FATAL_ERR;
864 }
865
866 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
867 {
868 /*
869 * Show that we at least got one token
870 */
871 iTokens = 1;
872
873 /*
874 * Search for configuration keywords
875 */
876 if(!strcmp(PORTS, pcToken))
877 {
878 PROTO_CONF *ports = (PROTO_CONF*)GlobalConf->telnet_config;
879 iRet = ProcessPorts(ports, ErrorString, ErrStrLen);
880 if (iRet)
881 {
882 return iRet;
883 }
884 }
885 else if(!strcmp(AYT_THRESHOLD, pcToken))
886 {
887 iRet = ProcessTelnetAYTThreshold(GlobalConf->telnet_config,
888 ErrorString, ErrStrLen);
889 if (iRet)
890 {
891 return iRet;
892 }
893 }
894 else if(!strcmp(NORMALIZE, pcToken))
895 {
896 GlobalConf->telnet_config->normalize = 1;
897 }
898 else if(!strcmp(DETECT_ANOMALIES, pcToken))
899 {
900 GlobalConf->telnet_config->detect_anomalies = 1;
901 }
902 /*
903 * Start the CONF_OPT configurations.
904 */
905 else
906 {
907 snprintf(ErrorString, ErrStrLen,
908 "Invalid keyword '%s' for '%s' configuration.",
909 pcToken, GLOBAL);
910
911 return FTPP_FATAL_ERR;
912 }
913 }
914
915 /*
916 * If there are not any tokens to the configuration, then
917 * we let the user know and log the error. return non-fatal
918 * error.
919 */
920 if(!iTokens)
921 {
922 snprintf(ErrorString, ErrStrLen,
923 "No tokens to '%s' configuration.", TELNET);
924 return FTPP_NONFATAL_ERR;
925 }
926
927 /* Let's print out the telnet config */
928 PrintTelnetConf(GlobalConf->telnet_config);
929
930 return FTPP_SUCCESS;
931 }
932
933 #if 0
934 /**obsoleted during changes for bug_31418
935 */
936 /*
937 * Function: GetIPAddr(char *addrString, unsigned uint32_t *ipAddr,
938 * char *ErrorString, int ErrStrLen)
939 *
940 * Purpose: This is where we convert an IP address to a numeric
941 *
942 * Any errors that are encountered are specified in the error
943 * string and the type of error is returned through the return
944 * code, i.e. fatal, non-fatal.
945 *
946 * Arguments: addrString => pointer to the address string
947 * ipAddr => pointer to converted address
948 * ErrorString => error string buffer
949 * ErrStrLen => the length of the error string buffer
950 *
951 * Returns: int => an error code integer (0 = success,
952 * >0 = non-fatal error, <0 = fatal error)
953 *
954 */
955 static int GetIPAddr(char *addrString, sfaddr_t *ipAddr,
956 char *ErrorString, int ErrStrLen)
957 {
958 if(sfip_pton(addrString, ipAddr) != SFIP_SUCCESS)
959 {
960 snprintf(ErrorString, ErrStrLen,
961 "Invalid FTP client IP address '%s'.", addrString);
962
963 return FTPP_FATAL_ERR;
964 }
965
966 return FTPP_SUCCESS;
967 }
968 #endif
969 /*
970 * Function: ProcessFTPCmdList(FTP_SERVER_PROTO_CONF *ServerConf,
971 * char *confOption,
972 * char *ErrorString, int ErrStrLen,
973 * int require_cmds, int require_length)
974 *
975 * Purpose: Process the FTP cmd lists for the client configuration.
976 * This configuration is a parameter length for the list of
977 * FTP commands and is ended by a delimiter.
978 *
979 * Arguments: ServerConf => pointer to the FTP server configuration
980 * confOption => pointer to the name of the option
981 * ErrorString => error string buffer
982 * ErrStrLen => the length of the error string buffer
983 * require_cmds => flag to require a command list
984 * require_length => flag to require a length specifier
985 *
986 * Returns: int => an error code integer (0 = success,
987 * >0 = non-fatal error, <0 = fatal error)
988 *
989 */
ProcessFTPCmdList(FTP_SERVER_PROTO_CONF * ServerConf,char * confOption,char * ErrorString,int ErrStrLen,int require_cmds,int require_length)990 static int ProcessFTPCmdList(FTP_SERVER_PROTO_CONF *ServerConf,
991 char *confOption,
992 char *ErrorString, int ErrStrLen,
993 int require_cmds, int require_length)
994 {
995 FTP_CMD_CONF *FTPCmd = NULL;
996 char *pcToken;
997 char *pcEnd = NULL;
998 char *cmd;
999 int iLength = 0;
1000 int iEndCmds = 0;
1001 int iRet;
1002
1003 if (require_length)
1004 {
1005 pcToken = NextToken(CONF_SEPARATORS);
1006 if(!pcToken)
1007 {
1008 snprintf(ErrorString, ErrStrLen,
1009 "Invalid cmd list format.");
1010
1011 return FTPP_FATAL_ERR;
1012 }
1013
1014 iLength = strtol(pcToken, &pcEnd, 10);
1015
1016 /*
1017 * Let's check to see if the entire string was valid.
1018 * If there is an address here, then there was an
1019 * invalid character in the string.
1020 */
1021 if((*pcEnd) || (iLength < 0))
1022 {
1023 snprintf(ErrorString, ErrStrLen,
1024 "Invalid argument to token '%s'. "
1025 "Length must be a positive number",
1026 confOption);
1027
1028 return FTPP_FATAL_ERR;
1029 }
1030 }
1031
1032 if (require_cmds)
1033 {
1034 pcToken = NextToken(CONF_SEPARATORS);
1035 if(!pcToken)
1036 {
1037 snprintf(ErrorString, ErrStrLen,
1038 "Invalid cmd list format.");
1039
1040 return FTPP_FATAL_ERR;
1041 }
1042
1043 if(strcmp(START_PORT_LIST, pcToken))
1044 {
1045 snprintf(ErrorString, ErrStrLen,
1046 "Must start a cmd list with the '%s' token.",
1047 START_PORT_LIST);
1048
1049 return FTPP_FATAL_ERR;
1050 }
1051
1052 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
1053 {
1054 if(!strcmp(END_PORT_LIST, pcToken))
1055 {
1056 iEndCmds = 1;
1057 break;
1058 }
1059
1060 cmd = pcToken;
1061
1062 FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd,
1063 strlen(cmd), &iRet);
1064
1065 if (FTPCmd == NULL)
1066 {
1067 /* Add it to the list */
1068 // note that struct includes 1 byte for null, so just add len
1069 FTPCmd = (FTP_CMD_CONF *)_dpd.snortAlloc(1,
1070 sizeof(FTP_CMD_CONF)+strlen(cmd),
1071 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1072 if (FTPCmd == NULL)
1073 {
1074 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1075 *(_dpd.config_file), *(_dpd.config_line));
1076 }
1077
1078 strcpy(FTPCmd->cmd_name, cmd);
1079
1080 ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd,
1081 strlen(cmd), FTPCmd);
1082 FTPCmd->max_param_len = ServerConf->def_max_param_len;
1083 }
1084
1085 if (require_length)
1086 {
1087 FTPCmd->max_param_len = iLength;
1088 FTPCmd->max_param_len_overridden = 1;
1089 }
1090 }
1091
1092 if(!iEndCmds)
1093 {
1094 snprintf(ErrorString, ErrStrLen,
1095 "Must end '%s' configuration with '%s'.",
1096 FTP_CMDS, END_PORT_LIST);
1097
1098 return FTPP_FATAL_ERR;
1099 }
1100 }
1101
1102 if (!strcmp(confOption, MAX_PARAM_LEN))
1103 {
1104 ServerConf->def_max_param_len = iLength;
1105 /* Reset the max length to the default for all existing commands */
1106 FTPCmd = ftp_cmd_lookup_first(ServerConf->cmd_lookup, &iRet);
1107 while (FTPCmd)
1108 {
1109 if (!FTPCmd->max_param_len_overridden)
1110 {
1111 FTPCmd->max_param_len = ServerConf->def_max_param_len;
1112 }
1113 FTPCmd = ftp_cmd_lookup_next(ServerConf->cmd_lookup, &iRet);
1114 }
1115 }
1116
1117 return FTPP_SUCCESS;
1118 }
1119
1120 /*
1121 * Function: ResetStringFormat (FTP_PARAM_FMT *Fmt)
1122 *
1123 * Purpose: Recursively sets nodes that allow strings to nodes that check
1124 * for a string format attack within the FTP parameter validation tree
1125 *
1126 * Arguments: Fmt => pointer to the FTP Parameter configuration
1127 *
1128 * Returns: None
1129 *
1130 */
ResetStringFormat(FTP_PARAM_FMT * Fmt)1131 void ResetStringFormat (FTP_PARAM_FMT *Fmt)
1132 {
1133 int i;
1134 if (!Fmt)
1135 return;
1136
1137 if (Fmt->type == e_unrestricted)
1138 Fmt->type = e_strformat;
1139
1140 ResetStringFormat(Fmt->optional_fmt);
1141 for (i=0;i<Fmt->numChoices;i++)
1142 {
1143 ResetStringFormat(Fmt->choices[i]);
1144 }
1145 ResetStringFormat(Fmt->next_param_fmt);
1146 }
1147
1148 /*
1149 * Function: ProcessFTPDataChanCmdsList(FTP_SERVER_PROTO_CONF *ServerConf,
1150 * char *confOption,
1151 * char *ErrorString, int ErrStrLen)
1152 *
1153 * Purpose: Process the FTP cmd lists for the client configuration.
1154 * This configuration is an indicator of data channels, data transfer,
1155 * string format, encryption, or login commands.
1156 *
1157 * Arguments: ServerConf => pointer to the FTP server configuration
1158 * confOption => pointer to the name of the option
1159 * ErrorString => error string buffer
1160 * ErrStrLen => the length of the error string buffer
1161 *
1162 * Returns: int => an error code integer (0 = success,
1163 * >0 = non-fatal error, <0 = fatal error)
1164 *
1165 */
ProcessFTPDataChanCmdsList(FTP_SERVER_PROTO_CONF * ServerConf,char * confOption,char * ErrorString,int ErrStrLen)1166 static int ProcessFTPDataChanCmdsList(FTP_SERVER_PROTO_CONF *ServerConf,
1167 char *confOption,
1168 char *ErrorString, int ErrStrLen)
1169 {
1170 FTP_CMD_CONF *FTPCmd = NULL;
1171 char *pcToken;
1172 char *cmd;
1173 int iEndCmds = 0;
1174 int iRet;
1175
1176 pcToken = NextToken(CONF_SEPARATORS);
1177 if(!pcToken)
1178 {
1179 snprintf(ErrorString, ErrStrLen,
1180 "Invalid %s list format.", confOption);
1181
1182 return FTPP_FATAL_ERR;
1183 }
1184
1185 if(strcmp(START_PORT_LIST, pcToken))
1186 {
1187 snprintf(ErrorString, ErrStrLen,
1188 "Must start a %s list with the '%s' token.",
1189 confOption, START_PORT_LIST);
1190
1191 return FTPP_FATAL_ERR;
1192 }
1193
1194 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
1195 {
1196 if(!strcmp(END_PORT_LIST, pcToken))
1197 {
1198 iEndCmds = 1;
1199 break;
1200 }
1201
1202 cmd = pcToken;
1203
1204 FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd,
1205 strlen(cmd), &iRet);
1206
1207 if (FTPCmd == NULL)
1208 {
1209 /* Add it to the list */
1210 // note that struct includes 1 byte for null, so just add len
1211 FTPCmd = (FTP_CMD_CONF *)_dpd.snortAlloc(1,
1212 sizeof(FTP_CMD_CONF) + strlen(cmd),
1213 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1214 if (FTPCmd == NULL)
1215 {
1216 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1217 *(_dpd.config_file), *(_dpd.config_line));
1218 }
1219
1220 strcpy(FTPCmd->cmd_name, cmd);
1221
1222 FTPCmd->max_param_len = ServerConf->def_max_param_len;
1223
1224 ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd,
1225 strlen(cmd), FTPCmd);
1226 }
1227
1228 if (!strcmp(confOption, DATA_CHAN_CMD))
1229 FTPCmd->data_chan_cmd = 1;
1230 else if (!strcmp(confOption, DATA_XFER_CMD))
1231 FTPCmd->data_xfer_cmd = 1;
1232 else if (!strcmp(confOption, DATA_REST_CMD))
1233 FTPCmd->data_rest_cmd = 1;
1234 else if (!strcmp(confOption, FILE_PUT_CMD))
1235 {
1236 FTPCmd->data_xfer_cmd = 1;
1237 FTPCmd->file_put_cmd = 1;
1238 }
1239 else if (!strcmp(confOption, FILE_GET_CMD))
1240 {
1241 FTPCmd->data_xfer_cmd = 1;
1242 FTPCmd->file_get_cmd = 1;
1243 }
1244 else if (!strcmp(confOption, STRING_FORMAT))
1245 {
1246 FTP_PARAM_FMT *Fmt = FTPCmd->param_format;
1247 if (Fmt)
1248 {
1249 ResetStringFormat(Fmt);
1250 }
1251 else
1252 {
1253 Fmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
1254 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1255 if (Fmt == NULL)
1256 {
1257 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1258 *(_dpd.config_file), *(_dpd.config_line));
1259 }
1260
1261 Fmt->type = e_head;
1262 FTPCmd->param_format = Fmt;
1263
1264 Fmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
1265 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1266 if (Fmt == NULL)
1267 {
1268 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1269 *(_dpd.config_file), *(_dpd.config_line));
1270 }
1271
1272 Fmt->type = e_strformat;
1273 FTPCmd->param_format->next_param_fmt = Fmt;
1274 Fmt->prev_param_fmt = FTPCmd->param_format;
1275 }
1276 FTPCmd->check_validity = 1;
1277 }
1278 else if (!strcmp(confOption, ENCR_CMD))
1279 FTPCmd->encr_cmd = 1;
1280 else if (!strcmp(confOption, LOGIN_CMD))
1281 FTPCmd->login_cmd = 1;
1282 }
1283
1284 if(!iEndCmds)
1285 {
1286 snprintf(ErrorString, ErrStrLen,
1287 "Must end '%s' configuration with '%s'.",
1288 confOption, END_PORT_LIST);
1289
1290 return FTPP_FATAL_ERR;
1291 }
1292
1293 return FTPP_SUCCESS;
1294 }
1295
1296 /*
1297 * Function: ProcessFTPDirCmdsList(FTP_SERVER_PROTO_CONF *ServerConf,
1298 * char *confOption,
1299 * char *ErrorString, int ErrStrLen)
1300 *
1301 * Purpose: Process the FTP cmd lists for the client configuration.
1302 * This configuration is an indicator of commands used to
1303 * retrieve or update the current directory.
1304 *
1305 * Arguments: ServerConf => pointer to the FTP server configuration
1306 * confOption => pointer to the name of the option
1307 * ErrorString => error string buffer
1308 * ErrStrLen => the length of the error string buffer
1309 *
1310 * Returns: int => an error code integer (0 = success,
1311 * >0 = non-fatal error, <0 = fatal error)
1312 *
1313 */
ProcessFTPDirCmdsList(FTP_SERVER_PROTO_CONF * ServerConf,char * confOption,char * ErrorString,int ErrStrLen)1314 static int ProcessFTPDirCmdsList(FTP_SERVER_PROTO_CONF *ServerConf,
1315 char *confOption,
1316 char *ErrorString, int ErrStrLen)
1317 {
1318 FTP_CMD_CONF *FTPCmd = NULL;
1319 char *pcToken;
1320 char *pcEnd = NULL;
1321 char *cmd;
1322 int iCode;
1323 int iEndCmds = 0;
1324 int iRet;
1325
1326 pcToken = NextToken(CONF_SEPARATORS);
1327 if(!pcToken)
1328 {
1329 snprintf(ErrorString, ErrStrLen,
1330 "Invalid %s list format.", confOption);
1331
1332 return FTPP_FATAL_ERR;
1333 }
1334
1335 if(strcmp(START_PORT_LIST, pcToken))
1336 {
1337 snprintf(ErrorString, ErrStrLen,
1338 "Must start a %s list with the '%s' token.",
1339 confOption, START_PORT_LIST);
1340
1341 return FTPP_FATAL_ERR;
1342 }
1343
1344 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
1345 {
1346 if(!strcmp(END_PORT_LIST, pcToken))
1347 {
1348 iEndCmds = 1;
1349 break;
1350 }
1351
1352 cmd = pcToken;
1353
1354 FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd,
1355 strlen(cmd), &iRet);
1356
1357 if (FTPCmd == NULL)
1358 {
1359 /* Add it to the list */
1360 // note that struct includes 1 byte for null, so just add len
1361 FTPCmd = (FTP_CMD_CONF *)_dpd.snortAlloc(1,
1362 sizeof(FTP_CMD_CONF) + strlen(cmd),
1363 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1364 if (FTPCmd == NULL)
1365 {
1366 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1367 *(_dpd.config_file), *(_dpd.config_line));
1368 }
1369
1370 strcpy(FTPCmd->cmd_name, cmd);
1371
1372 FTPCmd->max_param_len = ServerConf->def_max_param_len;
1373
1374 ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd,
1375 strlen(cmd), FTPCmd);
1376 }
1377
1378 pcToken = NextToken(CONF_SEPARATORS);
1379
1380 if (!pcToken)
1381 {
1382 snprintf(ErrorString, ErrStrLen,
1383 "FTP Dir Cmds must have associated response code: '%s'.",
1384 cmd);
1385
1386 return FTPP_FATAL_ERR;
1387 }
1388
1389 iCode = strtol(pcToken, &pcEnd, 10);
1390
1391 /*
1392 * Let's check to see if the entire string was valid.
1393 * If there is an address here, then there was an
1394 * invalid character in the string.
1395 */
1396 if((*pcEnd) || (iCode < 0))
1397 {
1398 snprintf(ErrorString, ErrStrLen,
1399 "Invalid argument to token '%s'. "
1400 "Code must be a positive number",
1401 confOption);
1402
1403 return FTPP_FATAL_ERR;
1404 }
1405
1406 FTPCmd->dir_response = iCode;
1407 }
1408
1409 if(!iEndCmds)
1410 {
1411 snprintf(ErrorString, ErrStrLen,
1412 "Must end '%s' configuration with '%s'.",
1413 confOption, END_PORT_LIST);
1414
1415 return FTPP_FATAL_ERR;
1416 }
1417
1418 return FTPP_SUCCESS;
1419 }
1420
ProcessFTPIgnoreDataChan(FTP_SERVER_PROTO_CONF * ServerConf,char * confOption,char * ErrorString,int ErrStrLen)1421 static int ProcessFTPIgnoreDataChan(FTP_SERVER_PROTO_CONF *ServerConf,
1422 char *confOption,
1423 char *ErrorString, int ErrStrLen)
1424 {
1425 char *pcToken;
1426
1427 pcToken = NextToken(CONF_SEPARATORS);
1428 if (pcToken == NULL)
1429 {
1430 snprintf(ErrorString, ErrStrLen, "No argument provided to option '%s'. "
1431 "Argument must be 'yes' or 'no'.",
1432 confOption);
1433 return FTPP_FATAL_ERR;
1434 }
1435 if (!strcasecmp("yes", pcToken))
1436 {
1437 ServerConf->data_chan = 1;
1438 }
1439 else if (!strcasecmp("no", pcToken))
1440 {
1441 if (ServerConf->data_chan == 1)
1442 {
1443 snprintf(ErrorString, ErrStrLen, "Both 'data_chan' and "
1444 "'ignore_data_chan' configured with conflicting options.");
1445 return FTPP_FATAL_ERR;
1446 }
1447 ServerConf->data_chan = 0;
1448 }
1449 else
1450 {
1451 snprintf(ErrorString, ErrStrLen, "Invalid argument to token '%s'. "
1452 "Argument must be 'yes' or 'no'.", confOption);
1453 return FTPP_FATAL_ERR;
1454 }
1455
1456 return FTPP_SUCCESS;
1457 }
1458
1459 /*
1460 * Function: SetOptionalsNext(FTP_PARAM_FMT *ThisFmt,
1461 * FTP_PARAM_FMT *NextFmt,
1462 * FTP_PARAM_FMT **choices,
1463 * int numChoices)
1464 *
1465 * Purpose: Recursively updates the next value for nodes in the FTP
1466 * Parameter validation tree.
1467 *
1468 * Arguments: ThisFmt => pointer to an FTP parameter validation node
1469 * NextFmt => pointer to an FTP parameter validation node
1470 * choices => pointer to a list of FTP parameter
1471 * validation nodes
1472 * numChoices => the number of nodes in the list
1473 *
1474 * Returns: int => an error code integer (0 = success,
1475 * >0 = non-fatal error, <0 = fatal error)
1476 *
1477 */
SetOptionalsNext(FTP_PARAM_FMT * ThisFmt,FTP_PARAM_FMT * NextFmt,FTP_PARAM_FMT ** choices,int numChoices)1478 static void SetOptionalsNext(FTP_PARAM_FMT *ThisFmt, FTP_PARAM_FMT *NextFmt,
1479 FTP_PARAM_FMT **choices, int numChoices)
1480 {
1481 if (!ThisFmt)
1482 return;
1483
1484 if (ThisFmt->optional)
1485 {
1486 if (ThisFmt->next_param_fmt == NULL)
1487 {
1488 ThisFmt->next_param_fmt = NextFmt;
1489 if (numChoices)
1490 {
1491 ThisFmt->numChoices = numChoices;
1492 ThisFmt->choices = (FTP_PARAM_FMT **)_dpd.snortAlloc(numChoices,
1493 sizeof(FTP_PARAM_FMT *),
1494 PP_FTPTELNET,
1495 PP_MEM_CATEGORY_CONFIG);
1496 if (ThisFmt->choices == NULL)
1497 {
1498 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1499 *(_dpd.config_file), *(_dpd.config_line));
1500 }
1501
1502 memcpy(ThisFmt->choices, choices, sizeof(FTP_PARAM_FMT *) * numChoices);
1503 }
1504 }
1505 else
1506 {
1507 SetOptionalsNext(ThisFmt->next_param_fmt, NextFmt,
1508 choices, numChoices);
1509 }
1510 }
1511 else
1512 {
1513 int i;
1514 SetOptionalsNext(ThisFmt->optional_fmt, ThisFmt->next_param_fmt,
1515 ThisFmt->choices, ThisFmt->numChoices);
1516 for (i=0;i<ThisFmt->numChoices;i++)
1517 {
1518 SetOptionalsNext(ThisFmt->choices[i], ThisFmt,
1519 choices, numChoices);
1520 }
1521 SetOptionalsNext(ThisFmt->next_param_fmt, ThisFmt,
1522 choices, numChoices);
1523 }
1524 }
1525
1526 /*
1527 * Function: ProcessDateFormat(FTP_DATE_FMT *dateFmt,
1528 * FTP_DATE_FMT *LastNonOptFmt,
1529 * char **format)
1530 *
1531 * Purpose: Sets the value for nodes in the FTP Date validation tree.
1532 *
1533 * Arguments: dateFmt => pointer to an FTP date validation node
1534 * LastNonOptFmt => pointer to previous FTP date validation node
1535 * format => pointer to next part of date validation string
1536 * Updated on function exit.
1537 *
1538 * Returns: int => an error code integer (0 = success,
1539 * >0 = non-fatal error, <0 = fatal error)
1540 *
1541 */
ProcessDateFormat(FTP_DATE_FMT * dateFmt,FTP_DATE_FMT * LastNonOptFmt,char ** format)1542 static int ProcessDateFormat(FTP_DATE_FMT *dateFmt,
1543 FTP_DATE_FMT *LastNonOptFmt,
1544 char **format)
1545 {
1546 char *curr_format;
1547 int iRet = FTPP_SUCCESS;
1548 int curr_len = 0;
1549 char *curr_ch;
1550 char *start_ch;
1551 FTP_DATE_FMT *CurrFmt = dateFmt;
1552
1553 if (!dateFmt)
1554 return FTPP_INVALID_ARG;
1555
1556 if (!format || !*format)
1557 return FTPP_INVALID_ARG;
1558
1559 start_ch = curr_ch = *format;
1560
1561 while (*curr_ch != '\0')
1562 {
1563 switch (*curr_ch)
1564 {
1565 case 'n':
1566 case 'C':
1567 case '+':
1568 case '-':
1569 case '.':
1570 curr_len++;
1571 curr_ch++;
1572 break;
1573 case '[':
1574 curr_ch++;
1575 if (curr_len > 0)
1576 {
1577 FTP_DATE_FMT *OptFmt;
1578 OptFmt = (FTP_DATE_FMT *)_dpd.snortAlloc(1,
1579 sizeof(FTP_DATE_FMT),
1580 PP_FTPTELNET,
1581 PP_MEM_CATEGORY_CONFIG);
1582 if (OptFmt == NULL)
1583 {
1584 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1585 *(_dpd.config_file), *(_dpd.config_line));
1586 }
1587
1588 curr_format = (char *)_dpd.snortAlloc(curr_len + 1,
1589 sizeof(char),
1590 PP_FTPTELNET,
1591 PP_MEM_CATEGORY_CONFIG);
1592 if (curr_format == NULL)
1593 {
1594 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1595 *(_dpd.config_file), *(_dpd.config_line));
1596 }
1597
1598 strncpy(curr_format, start_ch, curr_len);
1599 CurrFmt->format_string = curr_format;
1600 CurrFmt->optional = OptFmt;
1601 OptFmt->prev = CurrFmt;
1602 iRet = ProcessDateFormat(OptFmt, CurrFmt, &curr_ch);
1603 if (iRet != FTPP_SUCCESS)
1604 {
1605 _dpd.snortFree(OptFmt, sizeof(FTP_DATE_FMT),
1606 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1607 _dpd.snortFree(curr_format,
1608 (curr_len + 1) * sizeof(char),
1609 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1610 return iRet;
1611 }
1612 curr_len = 0;
1613 }
1614 start_ch = curr_ch;
1615 break;
1616 case ']':
1617 curr_ch++;
1618 if (curr_len > 0)
1619 {
1620 curr_format = (char *)_dpd.snortAlloc(curr_len + 1,
1621 sizeof(char),
1622 PP_FTPTELNET,
1623 PP_MEM_CATEGORY_CONFIG);
1624 if (curr_format == NULL)
1625 {
1626 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1627 *(_dpd.config_file), *(_dpd.config_line));
1628 }
1629
1630 strncpy(curr_format, start_ch, curr_len);
1631 CurrFmt->format_string = curr_format;
1632 curr_len = 0;
1633 }
1634 *format = curr_ch;
1635 return FTPP_SUCCESS;
1636 break;
1637 case '{':
1638 curr_ch++;
1639 {
1640 FTP_DATE_FMT *NewFmt;
1641 NewFmt = (FTP_DATE_FMT *)_dpd.snortAlloc(1,
1642 sizeof(FTP_DATE_FMT),
1643 PP_FTPTELNET,
1644 PP_MEM_CATEGORY_CONFIG);
1645 if (NewFmt == NULL)
1646 {
1647 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1648 *(_dpd.config_file), *(_dpd.config_line));
1649 }
1650
1651 if (curr_len > 0)
1652 {
1653 curr_format = (char *)_dpd.snortAlloc(curr_len + 1,
1654 sizeof(char),
1655 PP_FTPTELNET,
1656 PP_MEM_CATEGORY_CONFIG);
1657 if (curr_format == NULL)
1658 {
1659 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1660 *(_dpd.config_file), *(_dpd.config_line));
1661 }
1662
1663 strncpy(curr_format, start_ch, curr_len);
1664 CurrFmt->format_string = curr_format;
1665 curr_len = 0;
1666 }
1667 else
1668 {
1669 CurrFmt->empty = 1;
1670 }
1671 NewFmt->prev = LastNonOptFmt;
1672 CurrFmt->next_a = NewFmt;
1673 iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch);
1674 if (iRet != FTPP_SUCCESS)
1675 {
1676 return iRet;
1677 }
1678 NewFmt = (FTP_DATE_FMT *)_dpd.snortAlloc(1,
1679 sizeof(FTP_DATE_FMT),
1680 PP_FTPTELNET,
1681 PP_MEM_CATEGORY_CONFIG);
1682 if (NewFmt == NULL)
1683 {
1684 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1685 *(_dpd.config_file), *(_dpd.config_line));
1686 }
1687
1688 NewFmt->prev = LastNonOptFmt;
1689 CurrFmt->next_b = NewFmt;
1690 iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch);
1691 if (iRet != FTPP_SUCCESS)
1692 {
1693 return iRet;
1694 }
1695
1696 NewFmt = (FTP_DATE_FMT *)_dpd.snortAlloc(1,
1697 sizeof(FTP_DATE_FMT),
1698 PP_FTPTELNET,
1699 PP_MEM_CATEGORY_CONFIG);
1700 if (NewFmt == NULL)
1701 {
1702 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1703 *(_dpd.config_file), *(_dpd.config_line));
1704 }
1705
1706 NewFmt->prev = CurrFmt;
1707 CurrFmt->next = NewFmt;
1708 iRet = ProcessDateFormat(NewFmt, CurrFmt, &curr_ch);
1709 if (iRet != FTPP_SUCCESS)
1710 {
1711 return iRet;
1712 }
1713 }
1714 break;
1715 case '}':
1716 curr_ch++;
1717 if (curr_len > 0)
1718 {
1719 curr_format = (char *)_dpd.snortAlloc(curr_len + 1,
1720 sizeof(char), PP_FTPTELNET,
1721 PP_MEM_CATEGORY_CONFIG);
1722 if (curr_format == NULL)
1723 {
1724 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1725 *(_dpd.config_file), *(_dpd.config_line));
1726 }
1727
1728 strncpy(curr_format, start_ch, curr_len);
1729 CurrFmt->format_string = curr_format;
1730 curr_len = 0;
1731 *format = curr_ch;
1732 return FTPP_SUCCESS;
1733 }
1734 else
1735 {
1736 CurrFmt->empty = 1;
1737 *format = curr_ch;
1738 return FTPP_SUCCESS;
1739 }
1740 break;
1741 case '|':
1742 curr_ch++;
1743 if (curr_len > 0)
1744 {
1745 curr_format = (char *)_dpd.snortAlloc(curr_len + 1,
1746 sizeof(char), PP_FTPTELNET,
1747 PP_MEM_CATEGORY_CONFIG);
1748 if (curr_format == NULL)
1749 {
1750 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1751 *(_dpd.config_file), *(_dpd.config_line));
1752 }
1753
1754 strncpy(curr_format, start_ch, curr_len);
1755 CurrFmt->format_string = curr_format;
1756 curr_len = 0;
1757 *format = curr_ch;
1758 return FTPP_SUCCESS;
1759 }
1760 else
1761 {
1762 CurrFmt->empty = 1;
1763 *format = curr_ch;
1764 return FTPP_SUCCESS;
1765 }
1766 break;
1767 default:
1768 /* Uh, shouldn't get this. */
1769 return FTPP_INVALID_ARG;
1770 break;
1771 }
1772 }
1773
1774 if (curr_len > 0)
1775 {
1776 curr_format = (char *)_dpd.snortAlloc(curr_len + 1, sizeof(char),
1777 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1778 if (curr_format == NULL)
1779 {
1780 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1781 *(_dpd.config_file), *(_dpd.config_line));
1782 }
1783
1784 strncpy(curr_format, start_ch, curr_len);
1785 CurrFmt->format_string = curr_format;
1786 start_ch = curr_ch;
1787 curr_len = 0;
1788 }
1789
1790 /* Should've closed all options & ORs */
1791 *format = curr_ch;
1792 return FTPP_SUCCESS;
1793 }
1794
1795 /*
1796 * Function: DoNextFormat(FTP_PARAM_FMT *ThisFmt, int allocated,
1797 * char *ErrorString, int ErrStrLen)
1798 *
1799 * Purpose: Processes the next FTP parameter validation node.
1800 *
1801 * Arguments: ThisFmt => pointer to an FTP parameter validation node
1802 * allocated => indicator whether the next node is allocated
1803 * ErrorString => error string buffer
1804 * ErrStrLen => the length of the error string buffer
1805 *
1806 * Returns: int => an error code integer (0 = success,
1807 * >0 = non-fatal error, <0 = fatal error)
1808 *
1809 */
DoNextFormat(FTP_PARAM_FMT * ThisFmt,int allocated,char * ErrorString,int ErrStrLen)1810 int DoNextFormat(FTP_PARAM_FMT *ThisFmt, int allocated,
1811 char *ErrorString, int ErrStrLen)
1812 {
1813 FTP_PARAM_FMT *NextFmt;
1814 int iRet = FTPP_SUCCESS;
1815 char *fmt = NextToken(CONF_SEPARATORS);
1816
1817 if (!fmt)
1818 return FTPP_INVALID_ARG;
1819
1820 if(!strcmp(END_CMD_FORMAT, fmt))
1821 {
1822 return FTPP_SUCCESS;
1823 }
1824
1825 if (!strcmp(fmt, OR_FMT))
1826 {
1827 return FTPP_OR_FOUND;
1828 }
1829
1830 if (!strcmp(fmt, END_OPT_FMT))
1831 {
1832 return FTPP_OPT_END_FOUND;
1833 }
1834
1835 if (!strcmp(fmt, END_CHOICE_FMT))
1836 {
1837 return FTPP_CHOICE_END_FOUND;
1838 }
1839
1840 if (!strcmp(fmt, START_OPT_FMT))
1841 {
1842 NextFmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
1843 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1844 if (NextFmt == NULL)
1845 {
1846 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1847 *(_dpd.config_file), *(_dpd.config_line));
1848 }
1849
1850 ThisFmt->optional_fmt = NextFmt;
1851 NextFmt->optional = 1;
1852 NextFmt->prev_param_fmt = ThisFmt;
1853 if (ThisFmt->optional)
1854 NextFmt->prev_optional = 1;
1855 iRet = DoNextFormat(NextFmt, 1, ErrorString, ErrStrLen);
1856 if (iRet != FTPP_OPT_END_FOUND)
1857 {
1858 return FTPP_INVALID_ARG;
1859 }
1860
1861 return DoNextFormat(ThisFmt, 0, ErrorString, ErrStrLen);
1862 }
1863
1864 if (!strcmp(fmt, START_CHOICE_FMT))
1865 {
1866 int numChoices = 1;
1867 do
1868 {
1869 FTP_PARAM_FMT **tmpChoices =
1870 (FTP_PARAM_FMT **)_dpd.snortAlloc(numChoices,
1871 sizeof(FTP_PARAM_FMT *),
1872 PP_FTPTELNET,
1873 PP_MEM_CATEGORY_CONFIG);
1874 if (tmpChoices == NULL)
1875 {
1876 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1877 *(_dpd.config_file), *(_dpd.config_line));
1878 }
1879
1880 if (ThisFmt->numChoices)
1881 {
1882 /* explicit check that we have enough room for copy */
1883 if (numChoices <= ThisFmt->numChoices)
1884 DynamicPreprocessorFatalMessage("%s(%d) => Can't do memcpy - index out of range \n",
1885 *(_dpd.config_file), *(_dpd.config_line));
1886
1887 memcpy(tmpChoices, ThisFmt->choices,
1888 sizeof(FTP_PARAM_FMT*) * ThisFmt->numChoices);
1889 }
1890 NextFmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
1891 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1892 if (NextFmt == NULL)
1893 {
1894 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1895 *(_dpd.config_file), *(_dpd.config_line));
1896 }
1897
1898 tmpChoices[numChoices-1] = NextFmt;
1899 if (ThisFmt->choices)
1900 _dpd.snortFree(ThisFmt->choices,
1901 (ThisFmt->numChoices * sizeof(FTP_PARAM_FMT *)),
1902 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1903 ThisFmt->numChoices = numChoices;
1904 ThisFmt->choices = tmpChoices;
1905 NextFmt->prev_param_fmt = ThisFmt;
1906 iRet = DoNextFormat(NextFmt, 1, ErrorString, ErrStrLen);
1907 numChoices++;
1908 }
1909 while (iRet == FTPP_OR_FOUND);
1910
1911 if (iRet != FTPP_CHOICE_END_FOUND)
1912 {
1913 return FTPP_INVALID_ARG;
1914 }
1915
1916 return DoNextFormat(ThisFmt, 0, ErrorString, ErrStrLen);
1917 }
1918
1919 if (!allocated)
1920 {
1921 NextFmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
1922 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1923 if (NextFmt == NULL)
1924 {
1925 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1926 *(_dpd.config_file), *(_dpd.config_line));
1927 }
1928
1929 NextFmt->prev_param_fmt = ThisFmt;
1930 ThisFmt->next_param_fmt = NextFmt;
1931 if (ThisFmt->optional)
1932 NextFmt->prev_optional = 1;
1933 }
1934 else
1935 {
1936 NextFmt = ThisFmt;
1937 }
1938
1939 /* If its not an end cmd, OR, START/END Opt...
1940 * it must be a parameter specification.
1941 */
1942 /* Setup the type & format specs */
1943 if (!strcmp(fmt, F_INT))
1944 {
1945 NextFmt->type = e_int;
1946 }
1947 else if (!strcmp(fmt, F_NUMBER))
1948 {
1949 NextFmt->type = e_number;
1950 }
1951 else if (!strcmp(fmt, F_CHAR))
1952 {
1953 char *chars_allowed = NextToken(CONF_SEPARATORS);
1954 if(!chars_allowed)
1955 {
1956 snprintf(ErrorString, ErrStrLen,
1957 "Illegal format '' for token '%s'.",
1958 CMD_VALIDITY);
1959 return FTPP_INVALID_ARG;
1960 }
1961
1962 NextFmt->type = e_char;
1963 NextFmt->format.chars_allowed = 0;
1964 while (*chars_allowed != 0)
1965 {
1966 int bitNum = (*chars_allowed & 0x1f);
1967 NextFmt->format.chars_allowed |= (1 << (bitNum-1));
1968 chars_allowed++;
1969 }
1970 }
1971 else if (!strcmp(fmt, F_DATE))
1972 {
1973 FTP_DATE_FMT *DateFmt;
1974 char *format = NextToken(CONF_SEPARATORS);
1975 NextFmt->type = e_date;
1976 DateFmt = (FTP_DATE_FMT *)_dpd.snortAlloc(1, sizeof(FTP_DATE_FMT),
1977 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
1978 if (DateFmt == NULL)
1979 {
1980 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
1981 *(_dpd.config_file), *(_dpd.config_line));
1982 }
1983
1984 NextFmt->format.date_fmt = DateFmt;
1985 iRet = ProcessDateFormat(DateFmt, NULL, &format);
1986 if (iRet)
1987 {
1988 snprintf(ErrorString, ErrStrLen,
1989 "Illegal format %s for token '%s'.",
1990 format, CMD_VALIDITY);
1991
1992 return FTPP_INVALID_ARG;
1993 }
1994 }
1995 else if ( *fmt == *F_LITERAL )
1996 {
1997 char* end = strchr(++fmt, *F_LITERAL);
1998 int len = end ? end - fmt : 0;
1999
2000 if ( len < 1 )
2001 {
2002 snprintf(
2003 ErrorString, ErrStrLen,
2004 "Illegal format '' for token '%s'.", CMD_VALIDITY
2005 );
2006 return FTPP_INVALID_ARG;
2007 }
2008 NextFmt->type = e_literal;
2009 NextFmt->format.literal = (char *)_dpd.snortAlloc(1, len + 1,
2010 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2011 if ( !NextFmt->format.literal )
2012 {
2013 DynamicPreprocessorFatalMessage(
2014 "%s(%d) => Failed to allocate memory\n",
2015 *(_dpd.config_file), *(_dpd.config_line)
2016 );
2017 }
2018 strncpy(NextFmt->format.literal, fmt, len);
2019 NextFmt->format.literal[len] = '\0';
2020 }
2021 else if (!strcmp(fmt, F_STRING))
2022 {
2023 NextFmt->type = e_unrestricted;
2024 }
2025 else if (!strcmp(fmt, F_HOST_PORT))
2026 {
2027 NextFmt->type = e_host_port;
2028 }
2029 else if (!strcmp(fmt, F_LONG_HOST_PORT))
2030 {
2031 NextFmt->type = e_long_host_port;
2032 }
2033 else if (!strcmp(fmt, F_EXTD_HOST_PORT))
2034 {
2035 NextFmt->type = e_extd_host_port;
2036 }
2037 else
2038 {
2039 snprintf(ErrorString, ErrStrLen,
2040 "Illegal format type %s for token '%s'.",
2041 fmt, CMD_VALIDITY);
2042
2043 return FTPP_INVALID_ARG;
2044 }
2045
2046 return DoNextFormat(NextFmt, 0, ErrorString, ErrStrLen);
2047 }
2048
2049 /*
2050 * Function: ProcessFTPCmdValidity(FTP_SERVER_PROTO_CONF *ServerConf,
2051 * char *ErrorString, int ErrStrLen)
2052 *
2053 * Purpose: Process the ftp cmd validity configuration.
2054 * This sets the FTP command parameter validation tree.
2055 *
2056 * Arguments: ServerConf => pointer to the FTP server configuration
2057 * confOption => pointer to the name of the option
2058 * ErrorString => error string buffer
2059 * ErrStrLen => the length of the error string buffer
2060 *
2061 * Returns: int => an error code integer (0 = success,
2062 * >0 = non-fatal error, <0 = fatal error)
2063 *
2064 */
ProcessFTPCmdValidity(FTP_SERVER_PROTO_CONF * ServerConf,char * ErrorString,int ErrStrLen)2065 static int ProcessFTPCmdValidity(FTP_SERVER_PROTO_CONF *ServerConf,
2066 char *ErrorString, int ErrStrLen)
2067 {
2068 FTP_CMD_CONF *FTPCmd = NULL;
2069 FTP_PARAM_FMT *HeadFmt = NULL;
2070 char *cmd;
2071 char *fmt;
2072 int iRet;
2073
2074 fmt = NextToken(CONF_SEPARATORS);
2075 if(fmt == NULL)
2076 {
2077 snprintf(ErrorString, ErrStrLen,
2078 "No argument to token '%s'.", CMD_VALIDITY);
2079
2080 return FTPP_FATAL_ERR;
2081 }
2082
2083 cmd = fmt;
2084
2085 fmt = NextToken(CONF_SEPARATORS);
2086 if(!fmt)
2087 {
2088 snprintf(ErrorString, ErrStrLen,
2089 "Invalid cmd validity format.");
2090
2091 return FTPP_FATAL_ERR;
2092 }
2093
2094 if(strcmp(START_CMD_FORMAT, fmt))
2095 {
2096 snprintf(ErrorString, ErrStrLen,
2097 "Must start a cmd validity with the '%s' token.",
2098 START_CMD_FORMAT);
2099
2100 return FTPP_FATAL_ERR;
2101 }
2102
2103 HeadFmt = (FTP_PARAM_FMT *)_dpd.snortAlloc(1, sizeof(FTP_PARAM_FMT),
2104 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2105 if (HeadFmt == NULL)
2106 {
2107 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
2108 *(_dpd.config_file), *(_dpd.config_line));
2109 }
2110
2111 HeadFmt->type = e_head;
2112
2113 iRet = DoNextFormat(HeadFmt, 0, ErrorString, ErrStrLen);
2114
2115 /* Need to check to be sure we got a complete command */
2116 if (iRet)
2117 {
2118 return FTPP_FATAL_ERR;
2119 }
2120
2121 SetOptionalsNext(HeadFmt, NULL, NULL, 0);
2122
2123 FTPCmd = ftp_cmd_lookup_find(ServerConf->cmd_lookup, cmd,
2124 strlen(cmd), &iRet);
2125 if (FTPCmd == NULL)
2126 {
2127 /* Add it to the list */
2128 // note that struct includes 1 byte for null, so just add len
2129 FTPCmd = (FTP_CMD_CONF *)_dpd.snortAlloc(1,
2130 sizeof(FTP_CMD_CONF)+strlen(cmd),
2131 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2132 if (FTPCmd == NULL)
2133 {
2134 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
2135 *(_dpd.config_file), *(_dpd.config_line));
2136 }
2137
2138 strcpy(FTPCmd->cmd_name, cmd);
2139
2140 FTPCmd->max_param_len = ServerConf->def_max_param_len;
2141 ftp_cmd_lookup_add(ServerConf->cmd_lookup, cmd, strlen(cmd), FTPCmd);
2142 }
2143
2144 FTPCmd->check_validity = 1;
2145 if (FTPCmd->param_format)
2146 {
2147 ftpp_ui_config_reset_ftp_cmd_format(FTPCmd->param_format);
2148 FTPCmd->param_format = NULL;
2149 }
2150 FTPCmd->param_format = HeadFmt;
2151
2152 return FTPP_SUCCESS;
2153 }
2154
2155 /*
2156 * Function: PrintFormatDate(FTP_DATE_FMT *DateFmt)
2157 *
2158 * Purpose: Recursively prints the FTP date validation tree
2159 *
2160 * Arguments: DateFmt => pointer to the date format node
2161 *
2162 * Returns: None
2163 *
2164 */
PrintFormatDate(char * buf,FTP_DATE_FMT * DateFmt)2165 static void PrintFormatDate(char *buf, FTP_DATE_FMT *DateFmt)
2166 {
2167 FTP_DATE_FMT *OptChild;
2168
2169 if (!DateFmt->empty)
2170 _dpd.printfappend(buf, BUF_SIZE, "%s", DateFmt->format_string);
2171
2172 if (DateFmt->optional)
2173 {
2174 OptChild = DateFmt->optional;
2175 _dpd.printfappend(buf, BUF_SIZE, "[");
2176 PrintFormatDate(buf, OptChild);
2177 _dpd.printfappend(buf, BUF_SIZE, "]");
2178 }
2179
2180 if (DateFmt->next_a)
2181 {
2182 if (DateFmt->next_b)
2183 _dpd.printfappend(buf, BUF_SIZE, "{");
2184 OptChild = DateFmt->next_a;
2185 PrintFormatDate(buf, OptChild);
2186 if (DateFmt->next_b)
2187 {
2188 _dpd.printfappend(buf, BUF_SIZE, "|");
2189 OptChild = DateFmt->next_b;
2190 PrintFormatDate(buf, OptChild);
2191 _dpd.printfappend(buf, BUF_SIZE, "}");
2192 }
2193 }
2194
2195 if (DateFmt->next)
2196 PrintFormatDate(buf, DateFmt->next);
2197 }
2198
2199 /*
2200 * Function: PrintCmdFmt(FTP_PARAM_FMT *CmdFmt)
2201 *
2202 * Purpose: Recursively prints the FTP command parameter validation tree
2203 *
2204 * Arguments: CmdFmt => pointer to the parameter validation node
2205 *
2206 * Returns: None
2207 *
2208 */
PrintCmdFmt(char * buf,FTP_PARAM_FMT * CmdFmt)2209 static void PrintCmdFmt(char *buf, FTP_PARAM_FMT *CmdFmt)
2210 {
2211 FTP_PARAM_FMT *OptChild;
2212
2213 switch(CmdFmt->type)
2214 {
2215 case e_int:
2216 _dpd.printfappend(buf, BUF_SIZE, " %s", F_INT);
2217 break;
2218 case e_number:
2219 _dpd.printfappend(buf, BUF_SIZE, " %s", F_NUMBER);
2220 break;
2221 case e_char:
2222 _dpd.printfappend(buf, BUF_SIZE, " %s 0x%x", F_CHAR,
2223 CmdFmt->format.chars_allowed);
2224 break;
2225 case e_date:
2226 _dpd.printfappend(buf, BUF_SIZE, " %s", F_DATE);
2227 PrintFormatDate(buf, CmdFmt->format.date_fmt);
2228 break;
2229 case e_literal:
2230 _dpd.printfappend(buf, BUF_SIZE, " %s 0x%x", F_LITERAL,
2231 CmdFmt->format.literal);
2232 break;
2233 case e_unrestricted:
2234 _dpd.printfappend(buf, BUF_SIZE, " %s", F_STRING);
2235 break;
2236 case e_strformat:
2237 _dpd.printfappend(buf, BUF_SIZE, " %s", F_STRING_FMT);
2238 break;
2239 case e_host_port:
2240 _dpd.printfappend(buf, BUF_SIZE, " %s", F_HOST_PORT);
2241 break;
2242 case e_long_host_port:
2243 _dpd.printfappend(buf, BUF_SIZE, " %s", F_LONG_HOST_PORT);
2244 break;
2245 case e_extd_host_port:
2246 _dpd.printfappend(buf, BUF_SIZE, " %s", F_EXTD_HOST_PORT);
2247 break;
2248 case e_head:
2249 break;
2250 default:
2251 break;
2252 }
2253
2254 if (CmdFmt->optional_fmt)
2255 {
2256 OptChild = CmdFmt->optional_fmt;
2257 _dpd.printfappend(buf, BUF_SIZE, "[");
2258 PrintCmdFmt(buf, OptChild);
2259 _dpd.printfappend(buf, BUF_SIZE, "]");
2260 }
2261
2262 if (CmdFmt->numChoices)
2263 {
2264 int i;
2265 _dpd.printfappend(buf, BUF_SIZE, "{");
2266 for (i=0;i<CmdFmt->numChoices;i++)
2267 {
2268 if (i)
2269 _dpd.printfappend(buf, BUF_SIZE, "|");
2270 OptChild = CmdFmt->choices[i];
2271 PrintCmdFmt(buf, OptChild);
2272 }
2273 _dpd.printfappend(buf, BUF_SIZE, "}");
2274 }
2275
2276 if (CmdFmt->next_param_fmt && CmdFmt->next_param_fmt->prev_optional)
2277 PrintCmdFmt(buf, CmdFmt->next_param_fmt);
2278
2279 }
2280
2281 /*
2282 * Function: ProcessFTPMaxRespLen(FTP_CLIENT_PROTO_CONF *ClientConf,
2283 * char *ErrorString, int ErrStrLen)
2284 *
2285 * Purpose: Process the max response length configuration
2286 * This sets the max length of an FTP response that we
2287 * will tolerate, before alerting.
2288 *
2289 * Arguments: ClientConf => pointer to the FTP client configuration
2290 * ErrorString => error string buffer
2291 * ErrStrLen => the length of the error string buffer
2292 *
2293 * Returns: int => an error code integer (0 = success,
2294 * >0 = non-fatal error, <0 = fatal error)
2295 *
2296 */
ProcessFTPMaxRespLen(FTP_CLIENT_PROTO_CONF * ClientConf,char * ErrorString,int ErrStrLen)2297 static int ProcessFTPMaxRespLen(FTP_CLIENT_PROTO_CONF *ClientConf,
2298 char *ErrorString, int ErrStrLen)
2299 {
2300 char *pcToken;
2301 char *pcEnd = NULL;
2302 long int max_resp_len;
2303
2304 pcToken = NextToken(CONF_SEPARATORS);
2305 if(pcToken == NULL)
2306 {
2307 snprintf(ErrorString, ErrStrLen,
2308 "No argument to token '%s'.", MAX_RESP_LEN);
2309
2310 return FTPP_FATAL_ERR;
2311 }
2312
2313 max_resp_len = _dpd.SnortStrtol(pcToken, &pcEnd, 10);
2314
2315 /*
2316 * Let's check to see if the entire string was valid.
2317 * If there is an address here, then there was an
2318 * invalid character in the string.
2319 */
2320 if ((*pcEnd) || (max_resp_len < 0) || (errno == ERANGE))
2321 {
2322 snprintf(ErrorString, ErrStrLen,
2323 "Invalid argument to token '%s'. Must be a positive "
2324 "number.", MAX_RESP_LEN);
2325
2326 return FTPP_FATAL_ERR;
2327 }
2328
2329 ClientConf->max_resp_len = (unsigned int)max_resp_len;
2330
2331 return FTPP_SUCCESS;
2332 }
2333
2334 /*
2335 * Function: ParseBounceTo(char *token, FTP_BOUNCE_TO*)
2336 *
2337 * Purpose: Extract the IP address, masking bits (CIDR format), and
2338 * port information from an FTP Bounce To configuration.
2339 *
2340 * Arguments: token => string pointer to the FTP bounce configuration
2341 * required format: IP/CIDR,port[,portHi]\0
2342 * FTP_BOUNCE_TO => populated with parsed data
2343 *
2344 * Returns: int => an error code integer (0 = success,
2345 * >0 = non-fatal error, <0 = fatal error)
2346 *
2347 */
ParseBounceTo(char * token,FTP_BOUNCE_TO * bounce)2348 int ParseBounceTo(char* token, FTP_BOUNCE_TO* bounce)
2349 {
2350 char **toks;
2351 int num_toks;
2352 long int port_lo;
2353 char *endptr = NULL;
2354 sfcidr_t tmp_ip;
2355
2356 toks = _dpd.tokenSplit(token, ",", 3, &num_toks, 0);
2357 if (num_toks < 2)
2358 return FTPP_INVALID_ARG;
2359
2360 if (sfip_pton(toks[0], &tmp_ip) != SFIP_SUCCESS)
2361 {
2362 _dpd.tokenFree(&toks, num_toks);
2363 return FTPP_INVALID_ARG;
2364 }
2365
2366 memcpy(&bounce->ip, &tmp_ip, sizeof(sfcidr_t));
2367
2368 port_lo = _dpd.SnortStrtol(toks[1], &endptr, 10);
2369 if ((errno == ERANGE) || (*endptr != '\0') ||
2370 (port_lo < 0) || (port_lo >= MAXPORTS))
2371 {
2372 _dpd.tokenFree(&toks, num_toks);
2373 return FTPP_INVALID_ARG;
2374 }
2375
2376 bounce->portlo = (unsigned short)port_lo;
2377
2378 if (num_toks == 3)
2379 {
2380 long int port_hi = _dpd.SnortStrtol(toks[2], &endptr, 10);
2381
2382 if ((errno == ERANGE) || (*endptr != '\0') ||
2383 (port_hi < 0) || (port_hi >= MAXPORTS))
2384 {
2385 _dpd.tokenFree(&toks, num_toks);
2386 return FTPP_INVALID_ARG;
2387 }
2388
2389 if (bounce->portlo != (unsigned short)port_hi)
2390 {
2391 bounce->porthi = (unsigned short)port_hi;
2392 if (bounce->porthi < bounce->portlo)
2393 {
2394 unsigned short tmp = bounce->porthi;
2395 bounce->porthi = bounce->portlo;
2396 bounce->portlo = tmp;
2397 }
2398 }
2399 }
2400
2401 _dpd.tokenFree(&toks, num_toks);
2402 return FTPP_SUCCESS;
2403 }
2404
2405 /*
2406 * Function: ProcessFTPAlowBounce(FTP_CLIENT_PROTO_CONF *ClientConf,
2407 * char *ErrorString, int ErrStrLen)
2408 *
2409 * Purpose: Process the FTP allow bounce configuration.
2410 * This creates an allow bounce node and adds it to the list for the
2411 * client configuration.
2412 *
2413 * Arguments: ClientConf => pointer to the FTP client configuration
2414 * ErrorString => error string buffer
2415 * ErrStrLen => the length of the error string buffer
2416 *
2417 * Returns: int => an error code integer (0 = success,
2418 * >0 = non-fatal error, <0 = fatal error)
2419 *
2420 */
ProcessFTPAllowBounce(FTP_CLIENT_PROTO_CONF * ClientConf,char * ErrorString,int ErrStrLen)2421 static int ProcessFTPAllowBounce(FTP_CLIENT_PROTO_CONF *ClientConf,
2422 char *ErrorString, int ErrStrLen)
2423 {
2424 char *pcToken;
2425 int iOneAddr = 0;
2426 int iEndList = 0;
2427 int iRet;
2428
2429 pcToken = NextToken(CONF_SEPARATORS);
2430 if(pcToken == NULL)
2431 {
2432 snprintf(ErrorString, ErrStrLen,
2433 "No argument to token '%s'.", ALLOW_BOUNCE);
2434
2435 return FTPP_FATAL_ERR;
2436 }
2437
2438 if(strcmp(START_PORT_LIST, pcToken))
2439 {
2440 snprintf(ErrorString, ErrStrLen,
2441 "Must start a %s list with the '%s' token.",
2442 ALLOW_BOUNCE, START_PORT_LIST);
2443
2444 return FTPP_FATAL_ERR;
2445 }
2446
2447 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
2448 {
2449 FTP_BOUNCE_TO *newBounce;
2450
2451 if(!strcmp(END_PORT_LIST, pcToken))
2452 {
2453 iEndList = 1;
2454 break;
2455 }
2456
2457 /* TODO: Maybe want to redo this with high-speed searcher for ip/port.
2458 * Would be great if we could handle both full addresses and
2459 * subnets quickly -- using CIDR format. Need something that would
2460 * return most specific match -- ie a specific host is more specific
2461 * than subnet.
2462 */
2463 newBounce = (FTP_BOUNCE_TO *)_dpd.snortAlloc(1, sizeof(FTP_BOUNCE_TO),
2464 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2465 if (newBounce == NULL)
2466 {
2467 snprintf(ErrorString, ErrStrLen,
2468 "Failed to allocate memory for Bounce");
2469 return FTPP_FATAL_ERR;
2470 }
2471
2472 iRet = ParseBounceTo(pcToken, newBounce);
2473 if (iRet)
2474 {
2475 snprintf(ErrorString, ErrStrLen,
2476 "Invalid argument to token '%s': %s", ALLOW_BOUNCE, pcToken);
2477 _dpd.snortFree(newBounce, sizeof(FTP_BOUNCE_TO),
2478 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2479 return FTPP_FATAL_ERR;
2480 }
2481
2482 iRet = ftp_bounce_lookup_add(
2483 ClientConf->bounce_lookup, &newBounce->ip, newBounce
2484 );
2485 if (iRet)
2486 {
2487 snprintf(ErrorString, ErrStrLen,
2488 "Failed to add configuration for Bounce object '%s'.", ALLOW_BOUNCE);
2489 _dpd.snortFree(newBounce, sizeof(FTP_BOUNCE_TO),
2490 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2491 return FTPP_FATAL_ERR;
2492 }
2493
2494 iOneAddr = 1;
2495 }
2496
2497 if(!iEndList)
2498 {
2499 snprintf(ErrorString, ErrStrLen,
2500 "Must end '%s' configuration with '%s'.",
2501 ALLOW_BOUNCE, END_PORT_LIST);
2502
2503 return FTPP_FATAL_ERR;
2504 }
2505
2506 if(!iOneAddr)
2507 {
2508 snprintf(ErrorString, ErrStrLen,
2509 "Must include at least one address in '%s' configuration.",
2510 ALLOW_BOUNCE);
2511
2512 return FTPP_FATAL_ERR;
2513 }
2514
2515 return FTPP_SUCCESS;
2516 }
2517
2518 /*
2519 * Function: PrintFTPClientConf(char * client,
2520 * FTP_CLIENT_PROTO_CONF *ClientConf)
2521 *
2522 * Purpose: Prints the FTP client configuration
2523 *
2524 * Arguments: client => string pointer to the client IP
2525 * ClientConf => pointer to the client configuration
2526 *
2527 * Returns: int => an error code integer (0 = success,
2528 * >0 = non-fatal error, <0 = fatal error)
2529 *
2530 */
PrintFTPClientConf(char * client,FTP_CLIENT_PROTO_CONF * ClientConf)2531 static int PrintFTPClientConf(char * client, FTP_CLIENT_PROTO_CONF *ClientConf)
2532 {
2533 FTP_BOUNCE_TO *FTPBounce;
2534 int iErr;
2535
2536 if(!ClientConf)
2537 {
2538 return FTPP_INVALID_ARG;
2539 }
2540
2541 if (!printedFTPHeader)
2542 {
2543 _dpd.logMsg(" FTP CONFIG:\n");
2544 printedFTPHeader = 1;
2545 }
2546
2547 _dpd.logMsg(" FTP Client: %s\n", client);
2548
2549 PrintConfOpt(&ClientConf->bounce, " Check for Bounce Attacks");
2550 PrintConfOpt(&ClientConf->telnet_cmds, " Check for Telnet Cmds");
2551 PrintConfOpt(&ClientConf->ignore_telnet_erase_cmds, " Ignore Telnet Cmd Operations");
2552 _dpd.logMsg(" Max Response Length: %d\n", ClientConf->max_resp_len);
2553
2554 FTPBounce = ftp_bounce_lookup_first(ClientConf->bounce_lookup, &iErr);
2555 if (FTPBounce)
2556 {
2557 _dpd.logMsg(" Allow FTP bounces to:\n");
2558
2559 while (FTPBounce)
2560 {
2561 char *addr_str;
2562 char bits_str[5];
2563 int bits;
2564 bits_str[0] = '\0';
2565
2566 addr_str = sfip_to_str(&FTPBounce->ip.addr);
2567 bits = (int)FTPBounce->ip.bits;
2568 if (bits != 128)
2569 {
2570 snprintf(bits_str, sizeof(bits_str), "/%d",
2571 (sfaddr_family(&FTPBounce->ip.addr) == AF_INET) ? ((bits >= 96) ? (bits - 96) : -1) : bits);
2572 }
2573 if (FTPBounce->porthi)
2574 {
2575 _dpd.logMsg(" Address: %s%s, Ports: %d-%d\n",
2576 addr_str, bits_str[0] ? bits_str : "",
2577 FTPBounce->portlo, FTPBounce->porthi);
2578 }
2579 else
2580 {
2581 _dpd.logMsg(" Address: %s%s, Port: %d\n",
2582 addr_str, bits_str[0] ? bits_str : "",
2583 FTPBounce->portlo);
2584 }
2585
2586 FTPBounce = ftp_bounce_lookup_next(ClientConf->bounce_lookup, &iErr);
2587 }
2588 }
2589
2590 return FTPP_SUCCESS;
2591 }
2592
2593 /*
2594 * Function: ProcessFTPClientOptions(FTP_CLIENT_PROTO_CONF *ClientConf,
2595 * char *ErrorString, int ErrStrLen)
2596 *
2597 * Purpose: This is where we process the specific ftp client configuration
2598 * for FTPTelnet.
2599 *
2600 * We set the values of the ftp client configuraiton here. Any errors
2601 * that are encountered are specified in the error string and the type
2602 * of error is returned through the return code, i.e. fatal, non-fatal.
2603 *
2604 * Arguments: ClientConf => pointer to the client configuration
2605 * ErrorString => error string buffer
2606 * ErrStrLen => the length of the error string buffer
2607 *
2608 * Returns: int => an error code integer (0 = success,
2609 * >0 = non-fatal error, <0 = fatal error)
2610 *
2611 */
ProcessFTPClientOptions(FTP_CLIENT_PROTO_CONF * ClientConf,char * ErrorString,int ErrStrLen)2612 int ProcessFTPClientOptions(FTP_CLIENT_PROTO_CONF *ClientConf,
2613 char *ErrorString, int ErrStrLen)
2614 {
2615 FTPTELNET_CONF_OPT *ConfOpt;
2616 int iRet;
2617 char *pcToken;
2618 int iTokens = 0;
2619
2620 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
2621 {
2622 /*
2623 * Show that we at least got one token
2624 */
2625 iTokens = 1;
2626
2627 /*
2628 * Search for configuration keywords
2629 */
2630 if(!strcmp(MAX_RESP_LEN, pcToken))
2631 {
2632 iRet = ProcessFTPMaxRespLen(ClientConf, ErrorString, ErrStrLen);
2633 if (iRet)
2634 {
2635 return iRet;
2636 }
2637 }
2638 else if (!strcmp(ALLOW_BOUNCE, pcToken))
2639 {
2640 iRet = ProcessFTPAllowBounce(ClientConf, ErrorString, ErrStrLen);
2641 if (iRet)
2642 {
2643 return iRet;
2644 }
2645 }
2646 /*
2647 * Start the CONF_OPT configurations.
2648 */
2649 else if(!strcmp(BOUNCE, pcToken))
2650 {
2651 ConfOpt = &ClientConf->bounce;
2652 iRet = ProcessConfOpt(ConfOpt, BOUNCE, ErrorString, ErrStrLen);
2653 if (iRet)
2654 {
2655 return iRet;
2656 }
2657 }
2658 else if(!strcmp(TELNET_CMDS, pcToken))
2659 {
2660 ConfOpt = &ClientConf->telnet_cmds;
2661 iRet = ProcessConfOpt(ConfOpt, TELNET_CMDS, ErrorString, ErrStrLen);
2662 if (iRet)
2663 {
2664 return iRet;
2665 }
2666 }
2667 else if(!strcmp(IGNORE_TELNET_CMDS, pcToken))
2668 {
2669 ConfOpt = &ClientConf->ignore_telnet_erase_cmds;
2670 iRet = ProcessConfOpt(ConfOpt, IGNORE_TELNET_CMDS, ErrorString, ErrStrLen);
2671 if (iRet)
2672 {
2673 return iRet;
2674 }
2675 }
2676 else
2677 {
2678 snprintf(ErrorString, ErrStrLen,
2679 "Invalid keyword '%s' for '%s' configuration.",
2680 pcToken, GLOBAL);
2681
2682 return FTPP_FATAL_ERR;
2683 }
2684 }
2685
2686 /*
2687 * If there are not any tokens to the configuration, then
2688 * we let the user know and log the error. return non-fatal
2689 * error.
2690 */
2691 if(!iTokens)
2692 {
2693 snprintf(ErrorString, ErrStrLen,
2694 "No tokens to '%s %s' configuration.", FTP, CLIENT);
2695
2696 return FTPP_NONFATAL_ERR;
2697 }
2698
2699 return FTPP_SUCCESS;
2700 }
2701
2702 /*
2703 * Function: ProcessFTPClientConf(FTPTELNET_GLOBAL_CONF *GlobalConf,
2704 * char *ErrorString, int ErrStrLen)
2705 *
2706 * Purpose: This is where we process the ftp client configuration for FTPTelnet.
2707 *
2708 * We set the values of the ftp client configuraiton here. Any errors
2709 * that are encountered are specified in the error string and the type
2710 * of error is returned through the return code, i.e. fatal, non-fatal.
2711 *
2712 * The configuration options that are dealt with here are:
2713 * ports { x } Ports on which to do FTP checks
2714 * telnet_cmds yes|no Detect telnet cmds on FTP command channel
2715 * ignore_telnet_erase_cmds yes|no Do not process telnet EAC and EAL
2716 * commands during normalization of FTP command
2717 * channel.
2718 * max_resp_len x Max response length
2719 * bounce yes|no Detect FTP bounce attacks
2720 * bounce_to IP port|port-range Allow FTP bounces to specified IP/ports
2721 * data_chan Ignore data channel OR coordinate with cmd chan
2722 *
2723 * Arguments: GlobalConf => pointer to the global configuration
2724 * ErrorString => error string buffer
2725 * ErrStrLen => the length of the error string buffer
2726 *
2727 * Returns: int => an error code integer (0 = success,
2728 * >0 = non-fatal error, <0 = fatal error)
2729 *
2730 */
ProcessFTPClientConf(struct _SnortConfig * sc,FTPTELNET_GLOBAL_CONF * GlobalConf,char * ErrorString,int ErrStrLen)2731 int ProcessFTPClientConf(struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *GlobalConf,
2732 char *ErrorString, int ErrStrLen)
2733 {
2734 int iRet;
2735 int retVal = 0;
2736 char *client;
2737 char client_list[STD_BUF];
2738 sfcidr_t ipAddr;
2739 char *pIpAddressList = NULL;
2740 char *pIpAddressList2 = NULL;
2741 char *brkt = NULL;
2742 char firstIpAddress = 1;
2743 FTP_CLIENT_PROTO_CONF *new_client_conf = NULL;
2744
2745 //char *ConfigParseResumePtr = NULL; // Use this if a default client conf is added
2746 char ip_list = 0;
2747 FTP_CLIENT_PROTO_CONF *ftp_conf = NULL;
2748
2749 /*
2750 * If not default, create one for this IP
2751 */
2752 client = NextToken(CONF_SEPARATORS);
2753
2754 if ( !client )
2755 {
2756 DynamicPreprocessorFatalMessage(
2757 "%s(%d) Missing ftp_telnet ftp client address.\n",
2758 *(_dpd.config_file), *(_dpd.config_line));
2759 }
2760 else if(strcmp(DEFAULT, client))
2761 {
2762 /*
2763 ** Convert string to IP address
2764 */
2765 /// get the first delimiter
2766 if(strcmp(START_IPADDR_LIST, client) == 0)
2767 {
2768 //list begin token matched
2769 ip_list = 1;
2770 if ((pIpAddressList = mystrtok(NULL, END_IPADDR_LIST)) == NULL)
2771 {
2772 snprintf(ErrorString, ErrStrLen,
2773 "Invalid IP Address list in '%s' token.", CLIENT);
2774
2775 retVal = FTPP_INVALID_ARG;
2776 goto _return;
2777 }
2778 }
2779 else
2780 {
2781 //list begin didn't match so this must be an IP address
2782 pIpAddressList = client;
2783 }
2784
2785 //ConfigParseResumePtr = pIpAddressList+strlen(pIpAddressList);
2786
2787 pIpAddressList2 = strdup(pIpAddressList);
2788 if (!pIpAddressList2)
2789 {
2790 snprintf(ErrorString, ErrStrLen,
2791 "Could not allocate memory for server configuration.");
2792
2793 retVal = FTPP_INVALID_ARG;
2794 goto _return;
2795 }
2796
2797
2798
2799 for (client = strtok_r(pIpAddressList2, CONF_SEPARATORS, &brkt);
2800 client;
2801 client = strtok_r(NULL, CONF_SEPARATORS, &brkt))
2802 {
2803
2804 if (sfip_pton(client, &ipAddr) != SFIP_SUCCESS)
2805 {
2806 snprintf(ErrorString, ErrStrLen,
2807 "Invalid IP to '%s' token.", CLIENT);
2808
2809 retVal = FTPP_INVALID_ARG;
2810 goto _return;
2811 }
2812
2813 /*
2814 ** allocate the memory for the client configuration
2815 */
2816 if (firstIpAddress)
2817 {
2818 // Write this IP into the buffer for printing
2819 snprintf(client_list, STD_BUF, "%s", client);
2820
2821 new_client_conf = (FTP_CLIENT_PROTO_CONF *)_dpd.snortAlloc(1,
2822 sizeof(FTP_CLIENT_PROTO_CONF),
2823 PP_FTPTELNET,
2824 PP_MEM_CATEGORY_CONFIG);
2825 if (new_client_conf == NULL)
2826 {
2827 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
2828 *(_dpd.config_file), *(_dpd.config_line));
2829 }
2830
2831 ftpp_ui_config_reset_ftp_client(new_client_conf, 1);
2832
2833 //process the first IP address as usual
2834 firstIpAddress = 0;
2835
2836 ftp_conf = new_client_conf;
2837 }
2838 else
2839 {
2840 // Write this IP into the buffer for printing
2841 snprintf(client_list + strlen(client_list), STD_BUF - strlen(client_list) , ", %s", client);
2842
2843 new_client_conf = ftp_conf;
2844 }
2845
2846
2847 ftpp_ui_config_add_ftp_client(GlobalConf, &ipAddr, new_client_conf);
2848
2849 //create a reference
2850 new_client_conf->referenceCount++;
2851 }
2852
2853 if (firstIpAddress)
2854 {
2855 //no IP address was found
2856 snprintf(ErrorString, ErrStrLen,
2857 "Invalid IP Address list in '%s' token.", CLIENT);
2858
2859 retVal = FTPP_INVALID_ARG;
2860 goto _return;
2861 }
2862 }
2863 else
2864 {
2865 /**default configuration */
2866
2867 if (GlobalConf->default_ftp_client != NULL)
2868 {
2869 snprintf(ErrorString, ErrStrLen,
2870 "Cannot configure '%s' settings more than once.", CLIENT);
2871
2872 retVal = FTPP_INVALID_ARG;
2873 goto _return;
2874 }
2875
2876 GlobalConf->default_ftp_client =
2877 (FTP_CLIENT_PROTO_CONF *)_dpd.snortAlloc(1,
2878 sizeof(FTP_CLIENT_PROTO_CONF),
2879 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
2880 if (GlobalConf->default_ftp_client == NULL)
2881 {
2882 DynamicPreprocessorFatalMessage("Out of memory trying to create "
2883 "default ftp client configuration.\n");
2884 }
2885
2886 ftpp_ui_config_reset_ftp_client(GlobalConf->default_ftp_client, 0);
2887 ftp_conf = GlobalConf->default_ftp_client;
2888
2889 //ConfigParseResumePtr = client+strlen(client);
2890 }
2891
2892 iRet = ProcessFTPClientOptions(ftp_conf, ErrorString, ErrStrLen);
2893 if (iRet < 0)
2894 {
2895 retVal = FTPP_INVALID_ARG;
2896 goto _return;
2897 }
2898
2899 /*
2900 * Let's print out the FTP config
2901 */
2902 if (ip_list)
2903 {
2904 client = &client_list[0];
2905 }
2906 else if (pIpAddressList2)
2907 {
2908 client = pIpAddressList2;
2909 }
2910 PrintFTPClientConf(client, ftp_conf);
2911
2912 _return:
2913 if (pIpAddressList2)
2914 {
2915 free(pIpAddressList2);
2916 }
2917 return retVal;
2918 }
2919
2920 /*
2921 * Function: PrintFTPServerConf(char * server,
2922 * FTP_SERVER_PROTO_CONF *ServerConf)
2923 *
2924 * Purpose: Prints the FTP server configuration
2925 *
2926 * Arguments: server => string pointer to the server IP
2927 * ServerConf => pointer to the server configuration
2928 *
2929 * Returns: int => an error code integer (0 = success,
2930 * >0 = non-fatal error, <0 = fatal error)
2931 *
2932 */
PrintFTPServerConf(char * server,FTP_SERVER_PROTO_CONF * ServerConf)2933 static int PrintFTPServerConf(char * server, FTP_SERVER_PROTO_CONF *ServerConf)
2934 {
2935 const char* spaf = "";
2936 char buf[BUF_SIZE+1];
2937 int iCtr;
2938 int iRet;
2939 FTP_CMD_CONF *FTPCmd;
2940
2941 if(!ServerConf)
2942 {
2943 return FTPP_INVALID_ARG;
2944 }
2945
2946 if (!printedFTPHeader)
2947 {
2948 _dpd.logMsg(" FTP CONFIG:\n");
2949 printedFTPHeader = 1;
2950 }
2951
2952 if ( _dpd.isPafEnabled() )
2953 spaf = " (PAF)";
2954
2955 _dpd.logMsg(" FTP Server: %s\n", server);
2956
2957 memset(buf, 0, BUF_SIZE+1);
2958 snprintf(buf, BUF_SIZE, " Ports%s: ", spaf);
2959
2960 /*
2961 * Print out all the applicable ports.
2962 */
2963 for(iCtr = 0; iCtr < MAXPORTS; iCtr++)
2964 {
2965 if(ServerConf->proto_ports.ports[iCtr])
2966 {
2967 _dpd.printfappend(buf, BUF_SIZE, "%d ", iCtr);
2968 }
2969 }
2970
2971 _dpd.logMsg("%s\n", buf);
2972
2973 PrintConfOpt(&ServerConf->telnet_cmds, " Check for Telnet Cmds");
2974 PrintConfOpt(&ServerConf->ignore_telnet_erase_cmds, " Ignore Telnet Cmd Operations");
2975 _dpd.logMsg(" Ignore open data channels: %s\n",
2976 ServerConf->data_chan ? "YES" : "NO");
2977
2978 if (ServerConf->print_commands)
2979 {
2980 _dpd.logMsg(" FTP Commands:\n");
2981
2982 FTPCmd = ftp_cmd_lookup_first(ServerConf->cmd_lookup, &iRet);
2983 while (FTPCmd != NULL)
2984 {
2985 memset(buf, 0, BUF_SIZE+1);
2986 snprintf(buf, BUF_SIZE, " %s { %d ",
2987 FTPCmd->cmd_name, FTPCmd->max_param_len);
2988 #ifdef PRINT_DEFAULT_CONFIGS
2989 if (FTPCmd->data_chan_cmd)
2990 snprintf(buf, BUF_SIZE, "%s data_chan ");
2991 if (FTPCmd->data_xfer_cmd)
2992 snprintf(buf, BUF_SIZE, "%s data_xfer ");
2993 if (FTPCmd->encr_cmd)
2994 snprintf(buf, BUF_SIZE, "%s encr ");
2995 #endif
2996
2997 if (FTPCmd->check_validity)
2998 {
2999 FTP_PARAM_FMT *CmdFmt = FTPCmd->param_format;
3000 while (CmdFmt != NULL)
3001 {
3002 PrintCmdFmt(buf, CmdFmt);
3003
3004 CmdFmt = CmdFmt->next_param_fmt;
3005 }
3006 }
3007 _dpd.logMsg("%s}\n", buf);
3008 FTPCmd = ftp_cmd_lookup_next(ServerConf->cmd_lookup, &iRet);
3009 }
3010 }
3011
3012 return FTPP_SUCCESS;
3013 }
3014
3015 /*
3016 * Function: ProcessFTPServerOptions(FTP_SERVER_PROTO_CONF *ServerConf,
3017 * char *ErrorString, int ErrStrLen)
3018 *
3019 * Purpose: This is where we process the specific ftp server configuration
3020 * for FTPTelnet.
3021 *
3022 * We set the values of the ftp server configuraiton here. Any errors
3023 * that are encountered are specified in the error string and the type
3024 * of error is returned through the return code, i.e. fatal, non-fatal.
3025 *
3026 * Arguments: ServerConf => pointer to the server configuration
3027 * ErrorString => error string buffer
3028 * ErrStrLen => the length of the error string buffer
3029 *
3030 * Returns: int => an error code integer (0 = success,
3031 * >0 = non-fatal error, <0 = fatal error)
3032 *
3033 */
ProcessFTPServerOptions(FTP_SERVER_PROTO_CONF * ServerConf,char * ErrorString,int ErrStrLen)3034 int ProcessFTPServerOptions(FTP_SERVER_PROTO_CONF *ServerConf,
3035 char *ErrorString, int ErrStrLen)
3036 {
3037 FTPTELNET_CONF_OPT *ConfOpt;
3038 int iRet = 0;
3039 char *pcToken;
3040 int iTokens = 0;
3041 int data_chan_configured = 0;
3042
3043 while ((pcToken = NextToken(CONF_SEPARATORS)) != NULL)
3044 {
3045 /*
3046 * Show that we at least got one token
3047 */
3048 iTokens = 1;
3049
3050 /*
3051 * Search for configuration keywords
3052 */
3053 if(!strcmp(PORTS, pcToken))
3054 {
3055 PROTO_CONF *ports = (PROTO_CONF*)&ServerConf->proto_ports;
3056 iRet = ProcessPorts(ports, ErrorString, ErrStrLen);
3057 if (iRet)
3058 {
3059 return iRet;
3060 }
3061 }
3062 else if(!strcmp(FTP_CMDS, pcToken))
3063 {
3064 iRet = ProcessFTPCmdList(ServerConf, FTP_CMDS, ErrorString, ErrStrLen, 1, 0);
3065 if (iRet)
3066 {
3067 return iRet;
3068 }
3069 }
3070 else if(!strcmp(MAX_PARAM_LEN, pcToken))
3071 {
3072 iRet = ProcessFTPCmdList(ServerConf, MAX_PARAM_LEN, ErrorString, ErrStrLen, 0, 1);
3073 if (iRet)
3074 {
3075 return iRet;
3076 }
3077 }
3078 else if(!strcmp(ALT_PARAM_LEN, pcToken))
3079 {
3080 iRet = ProcessFTPCmdList(ServerConf, ALT_PARAM_LEN, ErrorString, ErrStrLen, 1, 1);
3081 if (iRet)
3082 {
3083 return iRet;
3084 }
3085 }
3086 else if(!strcmp(CMD_VALIDITY, pcToken))
3087 {
3088 iRet = ProcessFTPCmdValidity(ServerConf, ErrorString, ErrStrLen);
3089 if (iRet)
3090 {
3091 return iRet;
3092 }
3093 }
3094 else if(!strcmp(STRING_FORMAT, pcToken))
3095 {
3096 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3097 if (iRet)
3098 {
3099 return iRet;
3100 }
3101 }
3102 else if (!strcmp(DATA_CHAN_CMD, pcToken))
3103 {
3104 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3105 if (iRet)
3106 {
3107 return iRet;
3108 }
3109 }
3110 else if (!strcmp(DATA_XFER_CMD, pcToken))
3111 {
3112 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3113 if (iRet)
3114 {
3115 return iRet;
3116 }
3117 }
3118 else if (!strcmp(DATA_REST_CMD, pcToken))
3119 {
3120 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3121 if (iRet)
3122 {
3123 return iRet;
3124 }
3125 }
3126 else if (!strcmp(FILE_PUT_CMD, pcToken))
3127 {
3128 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3129 if (iRet)
3130 {
3131 return iRet;
3132 }
3133 }
3134 else if (!strcmp(FILE_GET_CMD, pcToken))
3135 {
3136 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3137 if (iRet)
3138 {
3139 return iRet;
3140 }
3141 }
3142 else if (!strcmp(ENCR_CMD, pcToken))
3143 {
3144 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3145 if (iRet)
3146 {
3147 return iRet;
3148 }
3149 }
3150 else if (!strcmp(LOGIN_CMD, pcToken))
3151 {
3152 iRet = ProcessFTPDataChanCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3153 if (iRet)
3154 {
3155 return iRet;
3156 }
3157 }
3158 else if (!strcmp(DIR_CMD, pcToken))
3159 {
3160 iRet = ProcessFTPDirCmdsList(ServerConf, pcToken, ErrorString, ErrStrLen);
3161 if (iRet)
3162 {
3163 return iRet;
3164 }
3165 }
3166 else if (!strcmp(DATA_CHAN, pcToken))
3167 {
3168 if (data_chan_configured && ServerConf->data_chan == 0)
3169 {
3170 snprintf(ErrorString, ErrStrLen, "Both 'data_chan' and "
3171 "'ignore_data_chan' configured with conflicting options.");
3172 return FTPP_FATAL_ERR;
3173 }
3174 else
3175 {
3176 ServerConf->data_chan = 1;
3177 data_chan_configured = 1;
3178 }
3179 }
3180 else if (!strcmp(PRINT_CMDS, pcToken))
3181 {
3182 ServerConf->print_commands = 1;
3183 }
3184 else if (!strcmp(IGNORE_DATA_CHAN, pcToken))
3185 {
3186 iRet = ProcessFTPIgnoreDataChan(ServerConf, pcToken, ErrorString, ErrStrLen);
3187 if (iRet)
3188 {
3189 return iRet;
3190 }
3191 data_chan_configured = 1;
3192 }
3193
3194 /*
3195 * Start the CONF_OPT configurations.
3196 */
3197 else if(!strcmp(TELNET_CMDS, pcToken))
3198 {
3199 ConfOpt = &ServerConf->telnet_cmds;
3200 iRet = ProcessConfOpt(ConfOpt, TELNET_CMDS, ErrorString, ErrStrLen);
3201 if (iRet)
3202 {
3203 return iRet;
3204 }
3205 }
3206 else if(!strcmp(IGNORE_TELNET_CMDS, pcToken))
3207 {
3208 ConfOpt = &ServerConf->ignore_telnet_erase_cmds;
3209 iRet = ProcessConfOpt(ConfOpt, IGNORE_TELNET_CMDS, ErrorString, ErrStrLen);
3210 if (iRet)
3211 {
3212 return iRet;
3213 }
3214 }
3215 else
3216 {
3217 snprintf(ErrorString, ErrStrLen,
3218 "Invalid keyword '%s' for '%s' configuration.",
3219 pcToken, GLOBAL);
3220
3221 return FTPP_FATAL_ERR;
3222 }
3223 }
3224
3225 /*
3226 * If there are not any tokens to the configuration, then
3227 * we let the user know and log the error. return non-fatal
3228 * error.
3229 */
3230 if(!iTokens)
3231 {
3232 snprintf(ErrorString, ErrStrLen,
3233 "No tokens to '%s %s' configuration.", FTP, SERVER);
3234
3235 return FTPP_NONFATAL_ERR;
3236 }
3237
3238 return FTPP_SUCCESS;
3239 }
3240
parseFtpServerConfigStr(FTP_SERVER_PROTO_CONF * ftp_conf,char * ConfigParseResumePtr,char ip_list,char * ErrorString,int ErrStrLen)3241 int parseFtpServerConfigStr( FTP_SERVER_PROTO_CONF *ftp_conf, char *ConfigParseResumePtr,
3242 char ip_list, char *ErrorString, int ErrStrLen )
3243 {
3244 int iRet = 0;
3245 char *saveMaxToken = maxToken;
3246 size_t default_conf_len;
3247 char *default_conf_str = DefaultConf(&default_conf_len);
3248
3249 /* First, process the default configuration -- namely, the
3250 * list of FTP commands, and the parameter validation checks */
3251 maxToken = default_conf_str + default_conf_len;
3252 mystrtok(default_conf_str, CONF_SEPARATORS);
3253
3254 iRet = ProcessFTPServerOptions(ftp_conf, ErrorString, ErrStrLen);
3255
3256 _dpd.snortFree(default_conf_str, default_conf_len,
3257 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3258 maxToken = saveMaxToken;
3259
3260 if (iRet < 0)
3261 return iRet;
3262
3263 /* Okay, now we need to reset the mystrtok pointers so we can process
3264 * the specific server configuration. Quick hack/trick here: reset
3265 * the end of the client string to a conf separator, then call mystrtok.
3266 * That will reset mystrtok's internal pointer to the next token after
3267 * the client name, which is what we're expecting it to be.
3268 */
3269 if (ConfigParseResumePtr < maxToken)
3270 {
3271 /* only if there is data after the server/client name */
3272 if (ip_list)
3273 *ConfigParseResumePtr-- = END_IPADDR_LIST[0];
3274 else
3275 *ConfigParseResumePtr-- = CONF_SEPARATORS[0];
3276
3277 mystrtok(ConfigParseResumePtr, CONF_SEPARATORS);
3278 iRet = ProcessFTPServerOptions(ftp_conf, ErrorString, ErrStrLen);
3279 if (iRet < 0)
3280 return iRet;
3281 }
3282
3283 return iRet;
3284 }
3285
enableFtpTelnetPortStreamServices(struct _SnortConfig * sc,PROTO_CONF * pc,char * network,int direction)3286 void enableFtpTelnetPortStreamServices( struct _SnortConfig *sc, PROTO_CONF *pc, char *network, int direction )
3287 {
3288 uint32_t port;
3289
3290 for ( port = 0; port < MAXPORTS; port++ )
3291 {
3292 if( pc->ports[ port ] )
3293 {
3294 _dpd.streamAPI->register_reassembly_port( network, port, direction );
3295 _dpd.sessionAPI->enable_preproc_for_port( sc, PP_FTPTELNET, PROTO_BIT__TCP, port );
3296 }
3297 }
3298 }
3299
3300 /*
3301 * Function: ProcessFTPServerConf::
3302 *
3303 * Purpose: This is where we process the ftp server configuration for FTPTelnet.
3304 *
3305 * We set the values of the ftp server configuraiton here. Any
3306 * errors that are encountered are specified in the error string and
3307 * the type of error is returned through the return code, i.e. fatal,
3308 * non-fatal.
3309 *
3310 * The configuration options that are dealt with here are:
3311 * ports { x } Ports on which to do FTP checks
3312 * ftp_cmds { CMD1 CMD2 ... } Valid FTP commands
3313 * def_max_param_len x Default max param length
3314 * alt_max_param_len x { CMD1 ... } Override default max param len
3315 * for CMD
3316 * chk_str_fmt { CMD1 ...} Detect string format attacks for CMD
3317 * cmd_validity CMD < fmt > Check the parameter validity for CMD
3318 * fmt is as follows:
3319 * int Param is an int
3320 * char _chars Param is one of _chars
3321 * date _datefmt Param follows format specified where
3322 * # = Number, C=Char, []=optional, |=OR,
3323 * +-.=literal
3324 * [] Optional parameters
3325 * string Param is string (unrestricted)
3326 * data_chan Ignore data channel
3327 *
3328 * Arguments: GlobalConf => pointer to the global configuration
3329 * ErrorString => error string buffer
3330 * ErrStrLen => the length of the error string buffer
3331 *
3332 * Returns: int => an error code integer (0 = success,
3333 * >0 = non-fatal error, <0 = fatal error)
3334 *
3335 */
ProcessFTPServerConf(struct _SnortConfig * sc,FTPTELNET_GLOBAL_CONF * GlobalConf,char * ErrorString,int ErrStrLen)3336 int ProcessFTPServerConf( struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *GlobalConf,
3337 char *ErrorString, int ErrStrLen )
3338 {
3339 int iRet = 0;
3340 int retVal = 0;
3341 char *server;
3342 char server_list[STD_BUF];
3343 sfcidr_t ipAddr;
3344 char *pIpAddressList = NULL;
3345 char *pIpAddressList2 = NULL;
3346 char *brkt = NULL;
3347 char firstIpAddress = 1;
3348 FTP_SERVER_PROTO_CONF *new_server_conf = NULL;
3349 char *ConfigParseResumePtr = NULL;
3350 char ip_list = 0;
3351 FTP_SERVER_PROTO_CONF *ftp_conf = NULL;
3352
3353 /*
3354 * If not default, create one for this IP
3355 */
3356 server = NextToken(CONF_SEPARATORS);
3357
3358 if ( !server )
3359 {
3360 DynamicPreprocessorFatalMessage(
3361 "%s(%d) Missing ftp_telnet ftp server address.\n",
3362 *(_dpd.config_file), *(_dpd.config_line));
3363 }
3364 else if(strcmp(DEFAULT, server))
3365 {
3366 if(strcmp(START_IPADDR_LIST, server) == 0)
3367 {
3368 //list begin token matched
3369 ip_list = 1;
3370 if ((pIpAddressList = mystrtok(NULL, END_IPADDR_LIST)) == NULL)
3371 {
3372 snprintf(ErrorString, ErrStrLen,
3373 "Invalid IP Address list in '%s' token.", SERVER);
3374
3375 retVal = FTPP_INVALID_ARG;
3376 goto _return;
3377 }
3378 }
3379 else
3380 {
3381 //list begin didn't match so this must be an IP address
3382 pIpAddressList = server;
3383 }
3384
3385 ConfigParseResumePtr = pIpAddressList+strlen(pIpAddressList);
3386
3387 pIpAddressList2 = strdup(pIpAddressList);
3388 if (!pIpAddressList2)
3389 {
3390 snprintf(ErrorString, ErrStrLen,
3391 "Could not allocate memory for server configuration.");
3392
3393 retVal = FTPP_INVALID_ARG;
3394 goto _return;
3395 }
3396
3397 for (server = strtok_r(pIpAddressList2, CONF_SEPARATORS, &brkt);
3398 server;
3399 server = strtok_r(NULL, CONF_SEPARATORS, &brkt))
3400 {
3401 if (sfip_pton(server, &ipAddr) != SFIP_SUCCESS)
3402 {
3403 snprintf(ErrorString, ErrStrLen,
3404 "Invalid IP to '%s' token.", SERVER);
3405
3406 retVal = FTPP_INVALID_ARG;
3407 goto _return;
3408 }
3409
3410 if (firstIpAddress)
3411 {
3412 /* Write this IP into the buffer for printing */
3413 snprintf(server_list, STD_BUF, "%s", server);
3414
3415 new_server_conf = (FTP_SERVER_PROTO_CONF *)_dpd.snortAlloc(1,
3416 sizeof(FTP_SERVER_PROTO_CONF),
3417 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3418 if (new_server_conf == NULL)
3419 {
3420 DynamicPreprocessorFatalMessage("%s(%d) => Failed to allocate memory\n",
3421 *(_dpd.config_file), *(_dpd.config_line));
3422 }
3423
3424 ftpp_ui_config_reset_ftp_server(new_server_conf, 1);
3425
3426 new_server_conf->serverAddr = strdup(server);
3427 if (new_server_conf->serverAddr == NULL)
3428 {
3429 DynamicPreprocessorFatalMessage("ProcessFTPServerConf(): Out of memory allocing serverAddr.\n");
3430 }
3431
3432 ftp_conf = new_server_conf;
3433 iRet = parseFtpServerConfigStr( ftp_conf, ConfigParseResumePtr, ip_list, ErrorString, ErrStrLen );
3434 if (iRet)
3435 {
3436 retVal = iRet;
3437 goto _return;
3438 }
3439
3440 //process the first IP address as usual
3441 firstIpAddress = 0;
3442 }
3443 else
3444 {
3445 /* Write this IP into the buffer for printing */
3446 snprintf(server_list + strlen(server_list), STD_BUF - strlen(server_list) , ", %s", server);
3447
3448 new_server_conf = ftp_conf;
3449 }
3450
3451 ftpp_ui_config_add_ftp_server(GlobalConf, &ipAddr, new_server_conf);
3452 enableFtpTelnetPortStreamServices( sc, &ftp_conf->proto_ports, server,
3453 SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
3454
3455 //create a reference
3456 new_server_conf->referenceCount++;
3457 }
3458
3459 if (firstIpAddress)
3460 {
3461 //no IP address was found
3462 snprintf(ErrorString, ErrStrLen,
3463 "Invalid IP Address list in '%s' token.", CLIENT);
3464
3465 retVal = FTPP_INVALID_ARG;
3466 goto _return;
3467 }
3468 }
3469 else
3470 {
3471 if (GlobalConf->default_ftp_server != NULL)
3472 {
3473 snprintf(ErrorString, ErrStrLen,
3474 "Cannot configure '%s' settings more than once.", SERVER);
3475
3476 retVal = FTPP_INVALID_ARG;
3477 goto _return;
3478 }
3479
3480 GlobalConf->default_ftp_server =
3481 (FTP_SERVER_PROTO_CONF *)_dpd.snortAlloc(1,
3482 sizeof(FTP_SERVER_PROTO_CONF),
3483 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3484 if (GlobalConf->default_ftp_server == NULL)
3485 {
3486 DynamicPreprocessorFatalMessage("Out of memory trying to create "
3487 "default ftp server configuration.\n");
3488 }
3489
3490 ftpp_ui_config_reset_ftp_server(GlobalConf->default_ftp_server, 0);
3491 ftp_conf = GlobalConf->default_ftp_server;
3492 ConfigParseResumePtr = server+strlen(server);
3493 GlobalConf->default_ftp_server->serverAddr = strdup("default");
3494 if (GlobalConf->default_ftp_server->serverAddr == NULL)
3495 {
3496 _dpd.snortFree(GlobalConf->default_ftp_server,
3497 sizeof(FTP_SERVER_PROTO_CONF),
3498 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3499 DynamicPreprocessorFatalMessage("Out of memory trying to create "
3500 "default ftp server configuration.\n");
3501 }
3502 iRet = parseFtpServerConfigStr( ftp_conf, ConfigParseResumePtr, ip_list, ErrorString, ErrStrLen );
3503 if (iRet)
3504 {
3505 retVal = iRet;
3506 goto _return;
3507 }
3508
3509 enableFtpTelnetPortStreamServices( sc, &ftp_conf->proto_ports, NULL,
3510 SSN_DIR_FROM_SERVER | SSN_DIR_FROM_CLIENT );
3511 }
3512
3513 /*
3514 * Let's print out the FTP config
3515 */
3516 if (ip_list)
3517 {
3518 server = &server_list[0];
3519 }
3520 else if (pIpAddressList2)
3521 {
3522 server = pIpAddressList2;
3523 }
3524 PrintFTPServerConf(server, ftp_conf);
3525
3526 _return:
3527 if (pIpAddressList2)
3528 {
3529 free(pIpAddressList2);
3530 }
3531 return retVal;
3532 }
3533
3534 /*
3535 * Function: PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf)
3536 *
3537 * Purpose: Prints the FTPTelnet preprocessor global configuration
3538 *
3539 * Arguments: GlobalConf => pointer to the global configuration
3540 *
3541 * Returns: int => an error code integer (0 = success,
3542 * >0 = non-fatal error, <0 = fatal error)
3543 *
3544 */
PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF * GlobalConf)3545 int PrintFTPGlobalConf(FTPTELNET_GLOBAL_CONF *GlobalConf)
3546 {
3547 _dpd.logMsg("FTPTelnet Config:\n");
3548
3549 _dpd.logMsg(" GLOBAL CONFIG\n");
3550 _dpd.logMsg(" Inspection Type: %s\n",
3551 GlobalConf->inspection_type == FTPP_UI_CONFIG_STATELESS ?
3552 "stateless" : "stateful");
3553 PrintConfOpt(&GlobalConf->encrypted, "Check for Encrypted Traffic");
3554 _dpd.logMsg(" Continue to check encrypted data: %s\n",
3555 GlobalConf->check_encrypted_data ? "YES" : "NO");
3556
3557 return FTPP_SUCCESS;
3558 }
3559
FTPTelnetCleanupFTPCMDConf(void * ftpCmd)3560 void FTPTelnetCleanupFTPCMDConf(void *ftpCmd)
3561 {
3562 FTP_CMD_CONF *FTPCmd = (FTP_CMD_CONF *)ftpCmd;
3563 /* Free the FTP_PARAM_FMT stuff... */
3564 ftpp_ui_config_reset_ftp_cmd(FTPCmd);
3565
3566 _dpd.snortFree(FTPCmd, sizeof(FTP_CMD_CONF)+strlen(FTPCmd->cmd_name),
3567 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3568 }
3569
FTPTelnetCleanupFTPServerConf(void * serverConf)3570 void FTPTelnetCleanupFTPServerConf(void *serverConf)
3571 {
3572 FTP_SERVER_PROTO_CONF *ServerConf = (FTP_SERVER_PROTO_CONF*)serverConf;
3573 if (ServerConf == NULL)
3574 return;
3575
3576 free(ServerConf->serverAddr);
3577 ServerConf->serverAddr = NULL;
3578
3579 /* Iterate through each cmd_lookup for this server */
3580 ftp_cmd_lookup_cleanup(&ServerConf->cmd_lookup);
3581 }
3582
FTPTelnetCleanupFTPBounceTo(void * ftpBounce)3583 void FTPTelnetCleanupFTPBounceTo(void *ftpBounce)
3584 {
3585 FTP_BOUNCE_TO *FTPBounce = (FTP_BOUNCE_TO *)ftpBounce;
3586 _dpd.snortFree(FTPBounce, sizeof(FTP_BOUNCE_TO),
3587 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3588 }
3589
FTPTelnetCleanupFTPClientConf(void * clientConf)3590 void FTPTelnetCleanupFTPClientConf(void *clientConf)
3591 {
3592 FTP_CLIENT_PROTO_CONF *ClientConf = (FTP_CLIENT_PROTO_CONF*)clientConf;
3593 if (ClientConf == NULL)
3594 return;
3595
3596 /* Iterate through each bounce_lookup for this client */
3597 ftp_bounce_lookup_cleanup(&ClientConf->bounce_lookup);
3598 }
3599
FTPTelnetFreeConfigsPolicy(tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)3600 static int FTPTelnetFreeConfigsPolicy(
3601 tSfPolicyUserContextId config,
3602 tSfPolicyId policyId,
3603 void* pData
3604 )
3605 {
3606 FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData;
3607
3608 //do any housekeeping before freeing FTPTELNET_GLOBAL_CONF
3609 sfPolicyUserDataClear (config, policyId);
3610 FTPTelnetFreeConfig(pPolicyConfig);
3611
3612 return 0;
3613 }
3614
FTPTelnetFreeConfigs(tSfPolicyUserContextId GlobalConf)3615 void FTPTelnetFreeConfigs(tSfPolicyUserContextId GlobalConf)
3616 {
3617 if (GlobalConf == NULL)
3618 return;
3619
3620 sfPolicyUserDataFreeIterate(GlobalConf, FTPTelnetFreeConfigsPolicy);
3621
3622 sfPolicyConfigDelete(GlobalConf);
3623 }
3624
FTPTelnetFreeConfig(FTPTELNET_GLOBAL_CONF * GlobalConf)3625 void FTPTelnetFreeConfig(FTPTELNET_GLOBAL_CONF *GlobalConf)
3626 {
3627 if (GlobalConf == NULL)
3628 return;
3629
3630 if (GlobalConf->default_ftp_client != NULL)
3631 {
3632 FTPTelnetCleanupFTPClientConf((void *)GlobalConf->default_ftp_client);
3633 _dpd.snortFree(GlobalConf->default_ftp_client,
3634 sizeof(FTP_CLIENT_PROTO_CONF),
3635 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3636 }
3637
3638 if (GlobalConf->default_ftp_server != NULL)
3639 {
3640 FTPTelnetCleanupFTPServerConf((void *)GlobalConf->default_ftp_server);
3641 _dpd.snortFree(GlobalConf->default_ftp_server,
3642 sizeof(FTP_SERVER_PROTO_CONF),
3643 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3644 }
3645
3646 if (GlobalConf->telnet_config != NULL)
3647 _dpd.snortFree(GlobalConf->telnet_config, sizeof(TELNET_PROTO_CONF),
3648 PP_FTPTELNET, PP_MEM_CATEGORY_CONFIG);
3649
3650 ftpp_ui_client_lookup_cleanup(&GlobalConf->client_lookup);
3651 ftpp_ui_server_lookup_cleanup(&GlobalConf->server_lookup);
3652
3653 _dpd.snortFree(GlobalConf, sizeof(FTPTELNET_GLOBAL_CONF), PP_FTPTELNET,
3654 PP_MEM_CATEGORY_CONFIG);
3655 }
3656
3657 /*
3658 * Function: FTPTelnetCheckFTPCmdOptions(FTP_SERVER_PROTO_CONF *serverConf)
3659 *
3660 * Purpose: This checks that the FTP configuration provided has
3661 * options for CMDs that make sense:
3662 * -- check if max_len == 0 & there is a cmd_validity
3663 *
3664 * Arguments: serverConf => pointer to Server Configuration
3665 *
3666 * Returns: 0 => no errors
3667 * 1 => errors
3668 *
3669 */
FTPTelnetCheckFTPCmdOptions(FTP_SERVER_PROTO_CONF * serverConf)3670 int FTPTelnetCheckFTPCmdOptions(FTP_SERVER_PROTO_CONF *serverConf)
3671 {
3672 FTP_CMD_CONF *cmdConf;
3673 int iRet =0;
3674 int config_error = 0;
3675
3676 cmdConf = ftp_cmd_lookup_first(serverConf->cmd_lookup, &iRet);
3677 while (cmdConf && (iRet == FTPP_SUCCESS))
3678 {
3679 size_t len = strlen(cmdConf->cmd_name);
3680 if ( len > serverConf->max_cmd_len ) serverConf->max_cmd_len = len;
3681
3682 if (cmdConf->check_validity && (cmdConf->max_param_len == 0))
3683 {
3684 _dpd.errMsg("FTPConfigCheck() configuration for server '%s', "
3685 "command '%s' has max length of 0 and parameters to validate\n",
3686 serverConf->serverAddr, cmdConf->cmd_name);
3687 config_error = 1;
3688 }
3689 cmdConf = ftp_cmd_lookup_next(serverConf->cmd_lookup, &iRet);
3690 }
3691
3692 return config_error;
3693 }
3694
3695 /*
3696 * Function: FTPTelnetCheckFTPServerConfigs(void)
3697 *
3698 * Purpose: This checks that the FTP server configurations are reasonable
3699 *
3700 * Arguments: None
3701 *
3702 * Returns: -1 on error
3703 *
3704 */
FTPTelnetCheckFTPServerConfigs(struct _SnortConfig * sc,FTPTELNET_GLOBAL_CONF * config)3705 int FTPTelnetCheckFTPServerConfigs(struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *config)
3706 {
3707 FTP_SERVER_PROTO_CONF *serverConf;
3708 int iRet = 0;
3709 int rval;
3710
3711 if (config == NULL)
3712 return 0;
3713
3714 if ((rval = ftpp_ui_server_iterate(sc, config->server_lookup, _checkServerConfig, &iRet)))
3715 return rval;
3716
3717 serverConf = config->default_ftp_server;
3718 if (FTPTelnetCheckFTPCmdOptions(serverConf))
3719 {
3720 _dpd.errMsg("FTPConfigCheck(): invalid configuration for FTP commands\n");
3721 return -1;
3722 }
3723 return 0;
3724 }
3725
_checkServerConfig(struct _SnortConfig * sc,void * pData)3726 static int _checkServerConfig(struct _SnortConfig *sc, void *pData)
3727 {
3728 FTP_SERVER_PROTO_CONF *serverConf = (FTP_SERVER_PROTO_CONF *)pData;
3729
3730 if (FTPTelnetCheckFTPCmdOptions(serverConf))
3731 {
3732 _dpd.errMsg("FTPConfigCheck(): invalid configuration for FTP commands\n");
3733 return -1;
3734 }
3735 return 0;
3736 }
3737
3738 /*
3739 * Function: FTPConfigCheck(void)
3740 *
3741 * Purpose: This checks that the FTP configuration provided includes
3742 * the default configurations for Server & Client.
3743 *
3744 * Arguments: None
3745 *
3746 * Returns: None
3747 *
3748 */
FTPTelnetCheckConfigs(struct _SnortConfig * sc,void * pData,tSfPolicyId policyId)3749 int FTPTelnetCheckConfigs(struct _SnortConfig *sc, void* pData, tSfPolicyId policyId)
3750 {
3751 int rval;
3752 FTPTELNET_GLOBAL_CONF *pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)pData;
3753
3754 if ( pPolicyConfig == NULL )
3755 return 0;
3756
3757 if ((pPolicyConfig->default_ftp_server == NULL) ||
3758 (pPolicyConfig->default_ftp_client == NULL))
3759 {
3760 _dpd.errMsg("FTP/Telnet configuration requires "
3761 "default client and default server configurations.\n");
3762 return -1;
3763 }
3764 if ( pPolicyConfig->telnet_config == NULL )
3765 {
3766 ProcessTelnetConf(pPolicyConfig,"",0);
3767 }
3768
3769 if ((pPolicyConfig->telnet_config->ayt_threshold > 0) &&
3770 !pPolicyConfig->telnet_config->normalize)
3771 {
3772 _dpd.errMsg("WARNING: Telnet Configuration Check: using an "
3773 "AreYouThere threshold requires telnet normalization to be "
3774 "turned on.\n");
3775 }
3776 if ((pPolicyConfig->encrypted.alert != 0) &&
3777 !pPolicyConfig->telnet_config->normalize)
3778 {
3779 _dpd.errMsg("WARNING: Telnet Configuration Check: checking for "
3780 "encrypted traffic requires telnet normalization to be turned "
3781 "on.\n");
3782 }
3783 /* So we don't have to check it every time we use it */
3784 if ((!_dpd.streamAPI) || (_dpd.streamAPI->version < STREAM_API_VERSION5))
3785 {
3786 _dpd.errMsg("FTPConfigCheck() Streaming & reassembly must be "
3787 "enabled\n");
3788 return -1;
3789 }
3790
3791 _dpd.setParserPolicy(sc, policyId);
3792
3793 /* Add FTPTelnet into the preprocessor list */
3794 #ifdef TARGET_BASED
3795 if ( _dpd.fileAPI->get_max_file_depth(sc, true) >= 0 )
3796 {
3797 _dpd.addPreproc(sc, FTPDataTelnetChecks, PRIORITY_APPLICATION, PP_FTPTELNET, PROTO_BIT__TCP);
3798 s_ftpdata_eof_cb_id = _dpd.streamAPI->register_event_handler(SnortFTPData_EOF);
3799 s_ftpdata_flush_cb_id = _dpd.streamAPI->register_ftp_flush_cb(SnortFTPData_Flush);
3800 }
3801 else
3802 #endif
3803 {
3804 _dpd.addPreproc(sc, FTPTelnetChecks, PRIORITY_APPLICATION, PP_FTPTELNET, PROTO_BIT__TCP);
3805 }
3806
3807 if ((rval = FTPTelnetCheckFTPServerConfigs(sc, pPolicyConfig)))
3808 return rval;
3809
3810 _FTPTelnetAddPortsOfInterest(sc, pPolicyConfig, policyId);
3811 #ifdef TARGET_BASED
3812 _FTPTelnetAddService(sc, ftp_app_id, policyId);
3813 #endif
3814
3815 return 0;
3816
3817 }
3818
FTPConfigCheckPolicy(struct _SnortConfig * sc,tSfPolicyUserContextId config,tSfPolicyId policyId,void * pData)3819 static int FTPConfigCheckPolicy(
3820 struct _SnortConfig *sc,
3821 tSfPolicyUserContextId config,
3822 tSfPolicyId policyId,
3823 void* pData
3824 )
3825 {
3826 return FTPTelnetCheckConfigs(sc, pData, policyId);
3827 }
3828
FTPConfigCheck(struct _SnortConfig * sc)3829 int FTPConfigCheck(struct _SnortConfig *sc)
3830 {
3831 int rval;
3832
3833 if (ftp_telnet_config == NULL)
3834 return 0;
3835
3836 if ((rval = sfPolicyUserDataIterate (sc, ftp_telnet_config, FTPConfigCheckPolicy)))
3837 return rval;
3838
3839 return 0;
3840 }
3841
3842 /*
3843 * Function: LogFTPPEvents(FTPP_GEN_EVENTS *GenEvents,
3844 * int iGenerator)
3845 *
3846 * Purpose: This is the routine that logs FTP/Telnet Preprocessor (FTPP)
3847 * alerts through Snort.
3848 *
3849 * Every Session gets looked at for any logged events, and if
3850 * there are events to be logged then we select the one with the
3851 * highest priority.
3852 *
3853 * We use a generic event structure that we set for each different
3854 * event structure. This way we can use the same code for event
3855 * logging regardless of what type of event strucure we are dealing
3856 * with.
3857 *
3858 * The important things to know about this function is how to work
3859 * with the event queue. The number of unique events is contained
3860 * in the stack_count variable. So we loop through all the unique
3861 * events and find which one has the highest priority. During this
3862 * loop, we also re-initialize the individual event counts for the
3863 * next iteration, saving us time in a separate initialization phase.
3864 *
3865 * After we've iterated through all the events and found the one
3866 * with the highest priority, we then log that event through snort.
3867 *
3868 * We've mapped the FTPTelnet and the Snort alert IDs together, so
3869 * we can access them directly instead of having a more complex
3870 * mapping function.
3871 *
3872 * Arguments: GenEvents => pointer a list of events
3873 * iGenerator => Generator ID (Telnet or FTP)
3874 *
3875 * Returns: int => an error code integer (0 = success,
3876 * >0 = non-fatal error, <0 = fatal error)
3877 *
3878 */
LogFTPPEvents(FTPP_GEN_EVENTS * GenEvents,int iGenerator)3879 static inline int LogFTPPEvents(FTPP_GEN_EVENTS *GenEvents,
3880 int iGenerator)
3881 {
3882 FTPP_EVENT *OrigEvent;
3883 FTPP_EVENT *HiEvent = NULL;
3884 int iStackCnt;
3885 int iEvent;
3886 int iCtr;
3887
3888 /*
3889 * Now starts the generic event processing
3890 */
3891 iStackCnt = GenEvents->stack_count;
3892
3893 /*
3894 * IMPORTANT::
3895 * We have to check the stack count of the event queue before we process
3896 * an log.
3897 */
3898 if(iStackCnt == 0)
3899 {
3900 return FTPP_SUCCESS;
3901 }
3902
3903 /*
3904 * Cycle through the events and select the event with the highest
3905 * priority.
3906 */
3907 for(iCtr = 0; iCtr < iStackCnt; iCtr++)
3908 {
3909 iEvent = GenEvents->stack[iCtr];
3910 OrigEvent = &(GenEvents->events[iEvent]);
3911
3912 /*
3913 * Set the event to start off the comparison
3914 */
3915 if(!HiEvent)
3916 {
3917 HiEvent = OrigEvent;
3918 }
3919
3920 /*
3921 * This is our "comparison function". Log the event with the highest
3922 * priority.
3923 */
3924 if(OrigEvent->event_info->priority < HiEvent->event_info->priority)
3925 {
3926 HiEvent = OrigEvent;
3927 }
3928
3929 /*
3930 * IMPORTANT:
3931 * This is how we reset the events in the event queue.
3932 * If you miss this step, you can be really screwed.
3933 */
3934 OrigEvent->count = 0;
3935 }
3936
3937 if (!HiEvent)
3938 return FTPP_SUCCESS;
3939
3940 /*
3941 * We use the iEvent+1 because the event IDs between snort and
3942 * FTPTelnet are mapped off-by-one. They're mapped off-by one
3943 * because in the internal FTPTelnet queue, events are mapped
3944 * starting at 0. For some reason, it appears that the first
3945 * event can't be zero, so we use the internal value and add
3946 * one for snort.
3947 */
3948 iEvent = HiEvent->event_info->alert_id + 1;
3949
3950 /* GenID, SID, Rev, Classification, Pri, Msg, RuleInfo */
3951 _dpd.alertAdd(iGenerator,
3952 HiEvent->event_info->alert_sid, 1, /* Revision 1 */
3953 HiEvent->event_info->classification,
3954 HiEvent->event_info->priority,
3955 HiEvent->event_info->alert_str, NULL); /* No Rule info */
3956
3957 /*
3958 * Reset the event queue stack counter, in the case of pipelined
3959 * requests.
3960 */
3961 GenEvents->stack_count = 0;
3962
3963 return FTPP_SUCCESS;
3964 }
3965
3966 /*
3967 * Function: LogFTPEvents(FTP_SESSION *FtpSession)
3968 *
3969 * Purpose: This is the routine that logs FTP alerts through Snort.
3970 * It maps the event into a generic event and calls
3971 * LOGFTPPEvents().
3972 *
3973 * Arguments: FtpSession => pointer the session structure
3974 *
3975 * Returns: int => an error code integer (0 = success,
3976 * >0 = non-fatal error, <0 = fatal error)
3977 *
3978 */
LogFTPEvents(FTP_SESSION * FtpSession)3979 static inline int LogFTPEvents(FTP_SESSION *FtpSession)
3980 {
3981 FTPP_GEN_EVENTS GenEvents;
3982 int iGenerator;
3983 int iRet;
3984
3985 GenEvents.stack = FtpSession->event_list.stack;
3986 GenEvents.stack_count = FtpSession->event_list.stack_count;
3987 GenEvents.events = FtpSession->event_list.events;
3988 iGenerator = GENERATOR_SPP_FTPP_FTP;
3989
3990 iRet = LogFTPPEvents(&GenEvents, iGenerator);
3991
3992 /* Reset the count... */
3993 FtpSession->event_list.stack_count = 0;
3994
3995 return iRet;
3996 }
3997
3998 /*
3999 * Function: LogTelnetEvents(TELNET_SESSION *TelnetSession)
4000 *
4001 * Purpose: This is the routine that logs Telnet alerts through Snort.
4002 * It maps the event into a generic event and calls
4003 * LOGFTPPEvents().
4004 *
4005 * Arguments: TelnetSession => pointer the session structure
4006 *
4007 * Returns: int => an error code integer (0 = success,
4008 * >0 = non-fatal error, <0 = fatal error)
4009 *
4010 */
LogTelnetEvents(TELNET_SESSION * TelnetSession)4011 static inline int LogTelnetEvents(TELNET_SESSION *TelnetSession)
4012 {
4013 FTPP_GEN_EVENTS GenEvents;
4014 int iGenerator;
4015 int iRet;
4016 GenEvents.stack = TelnetSession->event_list.stack;
4017 GenEvents.stack_count = TelnetSession->event_list.stack_count;
4018 GenEvents.events = TelnetSession->event_list.events;
4019 iGenerator = GENERATOR_SPP_FTPP_TELNET;
4020
4021 iRet = LogFTPPEvents(&GenEvents, iGenerator);
4022
4023 /* Reset the count... */
4024 TelnetSession->event_list.stack_count = 0;
4025
4026 return iRet;
4027 }
4028
4029 /*
4030 * Function: SetSiInput(FTPP_SI_INPUT *SiInput, Packet *p)
4031 *
4032 * Purpose: This is the routine sets the source and destination IP
4033 * address and port pairs so as to determine the direction
4034 * of the FTP or telnet connection.
4035 *
4036 * Arguments: SiInput => pointer the session input structure
4037 * p => pointer to the packet structure
4038 *
4039 * Returns: int => an error code integer (0 = success,
4040 * >0 = non-fatal error, <0 = fatal error)
4041 *
4042 */
SetSiInput(FTPP_SI_INPUT * SiInput,SFSnortPacket * p)4043 static inline int SetSiInput(FTPP_SI_INPUT *SiInput, SFSnortPacket *p)
4044 {
4045 IP_COPY_VALUE(SiInput->sip, GET_SRC_IP(p));
4046 IP_COPY_VALUE(SiInput->dip, GET_DST_IP(p));
4047 SiInput->sport = p->src_port;
4048 SiInput->dport = p->dst_port;
4049
4050 /*
4051 * We now set the packet direction
4052 */
4053 if(p->stream_session &&
4054 _dpd.sessionAPI->get_session_flags(p->stream_session) & SSNFLAG_MIDSTREAM)
4055 {
4056 SiInput->pdir = FTPP_SI_NO_MODE;
4057 }
4058 else if(p->flags & FLAG_FROM_SERVER)
4059 {
4060 SiInput->pdir = FTPP_SI_SERVER_MODE;
4061 }
4062 else if(p->flags & FLAG_FROM_CLIENT)
4063 {
4064 SiInput->pdir = FTPP_SI_CLIENT_MODE;
4065 }
4066 else
4067 {
4068 SiInput->pdir = FTPP_SI_NO_MODE;
4069 }
4070
4071 return FTPP_SUCCESS;
4072
4073 }
4074
4075 /*
4076 * Function: do_detection(Packet *p)
4077 *
4078 * Purpose: This is the routine that directly performs the rules checking
4079 * for each of the FTP & telnet preprocessing modules.
4080 *
4081 * Arguments: p => pointer to the packet structure
4082 *
4083 * Returns: None
4084 *
4085 */
do_detection(SFSnortPacket * p)4086 void do_detection(SFSnortPacket *p)
4087 {
4088 //extern int do_detect;
4089 //extern OptTreeNode *otn_tmp;
4090 PROFILE_VARS;
4091
4092 /*
4093 * If we get here we either had a client or server request/response.
4094 * We do the detection here, because we're starting a new paradigm
4095 * about protocol decoders.
4096 *
4097 * Protocol decoders are now their own detection engine, since we are
4098 * going to be moving protocol field detection from the generic
4099 * detection engine into the protocol module. This idea scales much
4100 * better than having all these Packet struct field checks in the
4101 * main detection engine for each protocol field.
4102 */
4103 PREPROC_PROFILE_START(ftppDetectPerfStats);
4104 _dpd.detect(p);
4105
4106 _dpd.disableAllDetect(p);
4107 PREPROC_PROFILE_END(ftppDetectPerfStats);
4108 #ifdef PERF_PROFILING
4109 ftppDetectCalled = 1;
4110 #endif
4111 //otn_tmp = NULL;
4112
4113 /*
4114 * We set the global detection flag here so that if request pipelines
4115 * fail, we don't do any detection.
4116 */
4117 //do_detect = 0;
4118 }
4119
4120 /*
4121 * Function: SnortTelnet(FTPTELNET_GLOBAL_CONF *GlobalConf,
4122 * Packet *p,
4123 * int iInspectMode)
4124 *
4125 * Purpose: This is the routine that handles the protocol layer checks
4126 * for telnet.
4127 *
4128 * Arguments: GlobalConf => pointer the global configuration
4129 * p => pointer to the packet structure
4130 * iInspectMode => indicator whether this is a client or server
4131 * packet.
4132 *
4133 * Returns: int => an error code integer (0 = success,
4134 * >0 = non-fatal error, <0 = fatal error)
4135 *
4136 */
SnortTelnet(FTPTELNET_GLOBAL_CONF * GlobalConf,TELNET_SESSION * TelnetSession,SFSnortPacket * p,int iInspectMode)4137 int SnortTelnet(FTPTELNET_GLOBAL_CONF *GlobalConf, TELNET_SESSION *TelnetSession,
4138 SFSnortPacket *p, int iInspectMode)
4139 {
4140 int iRet;
4141 PROFILE_VARS;
4142
4143 #ifdef DUMP_BUFFER
4144 dumpBuffer(TELNET_DUMP,(const char *)p->payload,p->payload_size);
4145 #endif
4146
4147 if (!TelnetSession)
4148 {
4149 if (GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL)
4150 {
4151 return FTPP_NONFATAL_ERR;
4152 }
4153 else
4154 {
4155 return FTPP_INVALID_SESSION;
4156 }
4157 }
4158
4159 if (TelnetSession->encr_state && !GlobalConf->check_encrypted_data)
4160 {
4161 return FTPP_SUCCESS;
4162 }
4163
4164 PREPROC_PROFILE_START(telnetPerfStats);
4165
4166 if (!GlobalConf->telnet_config->normalize)
4167 {
4168 do_detection(p);
4169 }
4170 else
4171 {
4172 iRet = normalize_telnet(GlobalConf, TelnetSession, p,
4173 iInspectMode, FTPP_APPLY_TNC_ERASE_CMDS);
4174 if ((iRet == FTPP_SUCCESS) || (iRet == FTPP_NORMALIZED))
4175 {
4176 do_detection(p);
4177 }
4178 LogTelnetEvents(TelnetSession);
4179 }
4180 PREPROC_PROFILE_END(telnetPerfStats);
4181 #ifdef PERF_PROFILING
4182 if (ftppDetectCalled)
4183 {
4184 telnetPerfStats.ticks -= ftppDetectPerfStats.ticks;
4185 /* And Reset ticks to 0 */
4186 ftppDetectPerfStats.ticks = 0;
4187 ftppDetectCalled = 0;
4188 }
4189 #endif
4190
4191 return FTPP_SUCCESS;
4192 }
4193
4194 /*
4195 * Function: SnortFTP(FTPTELNET_GLOBAL_CONF *GlobalConf,
4196 * Packet *p,
4197 * int iInspectMode)
4198 *
4199 * Purpose: This is the routine that handles the protocol layer checks
4200 * for FTP.
4201 *
4202 * Arguments: GlobalConf => pointer the global configuration
4203 * p => pointer to the packet structure
4204 * iInspectMode => indicator whether this is a client or server
4205 * packet.
4206 *
4207 * Returns: int => an error code integer (0 = success,
4208 * >0 = non-fatal error, <0 = fatal error)
4209 *
4210 */
SnortFTP(FTPTELNET_GLOBAL_CONF * GlobalConf,FTP_SESSION * FTPSession,SFSnortPacket * p,int iInspectMode)4211 int SnortFTP(FTPTELNET_GLOBAL_CONF *GlobalConf, FTP_SESSION *FTPSession,
4212 SFSnortPacket *p, int iInspectMode)
4213 {
4214 int iRet;
4215 ssl_callback_interface_t *ssl_cb = (ssl_callback_interface_t *)_dpd.getSSLCallback();
4216 PROFILE_VARS;
4217
4218 if (!FTPSession ||
4219 FTPSession->server_conf == NULL ||
4220 FTPSession->client_conf == NULL)
4221 {
4222 return FTPP_INVALID_SESSION;
4223 }
4224
4225 if(((FTPSession->encr_state == AUTH_TLS_ENCRYPTED) ||
4226 (FTPSession->encr_state == AUTH_SSL_ENCRYPTED) ||
4227 (FTPSession->encr_state == AUTH_UNKNOWN_ENCRYPTED)) )
4228 {
4229 if ((iInspectMode == FTPP_SI_CLIENT_MODE) && FTPSession->encr_state_chello )
4230 {
4231 if (IsTlsClientHello(p->payload, p->payload + p->payload_size))
4232 {
4233 FTPSession->encr_state_chello = false;
4234 if(ssl_cb)
4235 ssl_cb->session_initialize(p, FTPSession, FTP_Set_flow_id);
4236 }
4237
4238 }
4239
4240 if( _dpd.streamAPI->is_session_decrypted(p->stream_session))
4241 FTPSession->encr_state = 0;
4242 else if (!GlobalConf->check_encrypted_data)
4243 return FTPP_SUCCESS;
4244 }
4245
4246 PREPROC_PROFILE_START(ftpPerfStats);
4247
4248 if (iInspectMode == FTPP_SI_SERVER_MODE)
4249 {
4250 DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
4251 "Server packet: %.*s\n", p->payload_size, p->payload));
4252
4253 // FIXTHIS breaks target-based non-standard ports
4254 //if ( !_dpd.isPafEnabled() )
4255 /* Force flush of client side of stream */
4256 _dpd.streamAPI->response_flush_stream(p);
4257 }
4258 else
4259 {
4260 if ( !_dpd.readyForProcess(p) )
4261 {
4262 DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
4263 "Client packet will be reassembled\n"));
4264 PREPROC_PROFILE_END(ftpPerfStats);
4265 return FTPP_SUCCESS;
4266 }
4267 else
4268 {
4269 DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
4270 "Client packet: rebuilt %s: %.*s\n",
4271 (p->flags & FLAG_REBUILT_STREAM) ? "yes" : "no",
4272 p->payload_size, p->payload));
4273 }
4274 }
4275
4276 iRet = initialize_ftp(FTPSession, p, iInspectMode);
4277 if (iRet)
4278 {
4279 LogFTPEvents(FTPSession);
4280
4281 PREPROC_PROFILE_END(ftpPerfStats);
4282 return iRet;
4283 }
4284
4285 iRet = check_ftp(FTPSession, p, iInspectMode);
4286 if (iRet == FTPP_SUCCESS)
4287 {
4288 /* Ideally, Detect(), called from do_detection, will look at
4289 * the cmd & param buffers, or the rsp & msg buffers. Current
4290 * architecture does not support this...
4291 * So, we call do_detection() here. Otherwise, we'd call it
4292 * from inside check_ftp -- each time we process a pipelined
4293 * FTP command.
4294 */
4295 do_detection(p);
4296 }
4297
4298 LogFTPEvents(FTPSession);
4299
4300 PREPROC_PROFILE_END(ftpPerfStats);
4301 #ifdef PERF_PROFILING
4302 if (ftppDetectCalled)
4303 {
4304 ftpPerfStats.ticks -= ftppDetectPerfStats.ticks;
4305 /* And Reset ticks to 0 */
4306 ftppDetectPerfStats.ticks = 0;
4307 ftppDetectCalled = 0;
4308 }
4309 #endif
4310
4311 return iRet;
4312 }
4313
4314 /*
4315 * Funtcion: SnortFTPTelnet
4316 *
4317 * Purpose: This function calls the FTPTelnet function that handles
4318 * the protocol layer checks for an FTP or Telnet session,
4319 * after determining which, if either, protocol applies.
4320 *
4321 * Arguments: GlobalConf => pointer the global configuration
4322 * p => pointer to the packet structure
4323 *
4324 * Returns: int => an error code integer (0 = success,
4325 * >0 = non-fatal error, <0 = fatal error)
4326 *
4327 */
SnortFTPTelnet(SFSnortPacket * p)4328 int SnortFTPTelnet(SFSnortPacket *p)
4329 {
4330 FTPP_SI_INPUT SiInput;
4331 int iInspectMode = FTPP_SI_NO_MODE;
4332 FTP_TELNET_SESSION *ft_ssn = NULL;
4333 tSfPolicyId policy_id = _dpd.getNapRuntimePolicy();
4334 FTPTELNET_GLOBAL_CONF *GlobalConf = NULL;
4335
4336 #ifdef DUMP_BUFFER
4337 dumpBufferInit();
4338 #endif
4339
4340 sfPolicyUserPolicySet (ftp_telnet_config, policy_id);
4341 GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGetCurrent(ftp_telnet_config);
4342
4343 /*
4344 * Set up the FTPP_SI_INPUT pointer. This is what the session_inspection()
4345 * routines use to determine client and server traffic. Plus, this makes
4346 * the FTPTelnet library very independent from snort.
4347 */
4348 SetSiInput(&SiInput, p);
4349
4350 if (p->stream_session)
4351 {
4352 ft_ssn = (FTP_TELNET_SESSION *)
4353 _dpd.sessionAPI->get_application_data(p->stream_session, PP_FTPTELNET);
4354
4355 if (ft_ssn != NULL)
4356 {
4357 SiInput.pproto = ft_ssn->proto;
4358
4359 if (ft_ssn->proto == FTPP_SI_PROTO_TELNET)
4360 {
4361 TELNET_SESSION *telnet_ssn = (TELNET_SESSION *)ft_ssn;
4362
4363 GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(telnet_ssn->global_conf, telnet_ssn->policy_id);
4364
4365 if (SiInput.pdir != FTPP_SI_NO_MODE)
4366 {
4367 iInspectMode = SiInput.pdir;
4368 }
4369 else
4370 {
4371 if ((telnet_ssn->telnet_conf != NULL) &&
4372 (telnet_ssn->telnet_conf->proto_ports.ports[SiInput.sport]))
4373 {
4374 iInspectMode = FTPP_SI_SERVER_MODE;
4375 }
4376 else if ((telnet_ssn->telnet_conf != NULL) &&
4377 (telnet_ssn->telnet_conf->proto_ports.ports[SiInput.dport]))
4378 {
4379 iInspectMode = FTPP_SI_CLIENT_MODE;
4380 }
4381 }
4382 }
4383 else if (ft_ssn->proto == FTPP_SI_PROTO_FTP)
4384 {
4385 FTP_SESSION *ftp_ssn = (FTP_SESSION *)ft_ssn;
4386
4387 GlobalConf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ftp_ssn->global_conf, ftp_ssn->policy_id);
4388
4389 if (SiInput.pdir != FTPP_SI_NO_MODE)
4390 {
4391 iInspectMode = SiInput.pdir;
4392 }
4393 else
4394 {
4395 if ((ftp_ssn->server_conf != NULL) &&
4396 ftp_ssn->server_conf->proto_ports.ports[SiInput.sport])
4397 {
4398 iInspectMode = FTPP_SI_SERVER_MODE;
4399 }
4400 else if ((ftp_ssn->server_conf != NULL) &&
4401 ftp_ssn->server_conf->proto_ports.ports[SiInput.dport])
4402 {
4403 iInspectMode = FTPP_SI_CLIENT_MODE;
4404 }
4405 else
4406 {
4407 iInspectMode = FTPGetPacketDir(p);
4408 }
4409 }
4410 }
4411 else
4412 {
4413 /* XXX - Not FTP or Telnet */
4414 _dpd.sessionAPI->set_application_data(p->stream_session, PP_FTPTELNET, NULL, NULL);
4415 return 0;
4416 }
4417 }
4418 }
4419
4420 if (GlobalConf == NULL)
4421 return 0;
4422
4423 /*
4424 * FTPTelnet PACKET FLOW::
4425 *
4426 * Determine Proto Module::
4427 * The Session Inspection Module retrieves the appropriate
4428 * configuration for sessions, and takes care of the stateless
4429 * vs. stateful processing in order to do this. Once this module
4430 * does it's magic, we're ready for the primetime. This means
4431 * determining whether this is an FTP or a Telnet session.
4432 *
4433 * Proto Specific Module::
4434 * This is where we normalize the data. The Protocol specific module
4435 * handles what type of normalization to do (telnet, ftp) and does
4436 * protocol related checks.
4437 *
4438 */
4439 if (ft_ssn == NULL)
4440 {
4441 int iRet = ftpp_si_determine_proto(p, GlobalConf, &ft_ssn, &SiInput, &iInspectMode);
4442 if (iRet)
4443 return iRet;
4444 }
4445
4446 if (ft_ssn != NULL)
4447 {
4448 switch (SiInput.pproto)
4449 {
4450 case FTPP_SI_PROTO_TELNET:
4451 return SnortTelnet(GlobalConf, (TELNET_SESSION *)ft_ssn, p, iInspectMode);
4452 break;
4453 case FTPP_SI_PROTO_FTP:
4454 return SnortFTP(GlobalConf, (FTP_SESSION *)ft_ssn, p, iInspectMode);
4455 break;
4456 }
4457 }
4458
4459 /* Uh, shouldn't get here */
4460 return FTPP_INVALID_PROTO;
4461 }
4462
4463 #ifdef TARGET_BASED
FTPDataProcess(SFSnortPacket * p,FTP_DATA_SESSION * data_ssn,uint8_t * file_data,uint16_t data_length)4464 static void FTPDataProcess(SFSnortPacket *p, FTP_DATA_SESSION *data_ssn,
4465 uint8_t *file_data, uint16_t data_length)
4466 {
4467 int status;
4468
4469 _dpd.setFileDataPtr((uint8_t *)p->payload, (uint16_t)p->payload_size);
4470
4471 if(data_ssn->flags & FTPDATA_FLG_FLUSH)
4472 {
4473 _dpd.fileAPI->set_file_partial(p,data_ssn->position,data_ssn->direction,true);
4474 }
4475 if(data_ssn->flags & FTPDATA_FLG_STOP)
4476 {
4477 _dpd.fileAPI->set_file_partial(p,data_ssn->position,data_ssn->direction,false);
4478 }
4479 status = _dpd.fileAPI->file_process(p, (uint8_t *)file_data,
4480 data_length, data_ssn->position, data_ssn->direction, false, (data_ssn->flags & FTPDATA_FLG_FLUSH) ? true : false);
4481
4482 FTP_SESSION *ft_ssn = (FTP_SESSION *) _dpd.sessionAPI->get_application_data_from_key(data_ssn->ftp_key, PP_FTPTELNET);
4483 if(ft_ssn && (ft_ssn->flags & FTP_FLG_MALWARE_ENABLED) && _dpd.active_PacketWasDropped())
4484 {
4485 _dpd.fileAPI->file_resume_block_add_file(p, data_ssn->path_hash, 0, 0, 0, NULL, ft_ssn->control_clientPort,
4486 ft_ssn->control_serverPort, true , data_ssn->direction);
4487 }
4488
4489 /* Filename needs to be set AFTER the first call to file_process( ) */
4490 if (data_ssn->filename && !(data_ssn->flags & FTPDATA_FLG_FILENAME_SET))
4491 {
4492 _dpd.fileAPI->set_file_name(p->stream_session,
4493 (uint8_t *)data_ssn->filename, data_ssn->file_xfer_info, false);
4494 data_ssn->flags |= FTPDATA_FLG_FILENAME_SET;
4495 }
4496
4497 /* Ignore the rest of this transfer if file processing is complete
4498 * and preprocessor was configured to ignore ftp-data sessions. */
4499 if (!status && data_ssn->data_chan)
4500 {
4501 _dpd.sessionAPI->set_ignore_direction(
4502 p->stream_session, SSN_DIR_BOTH);
4503 }
4504 }
4505
SnortFTPData_EOF(SFSnortPacket * p)4506 void SnortFTPData_EOF(SFSnortPacket *p)
4507 {
4508 FTP_SESSION *ftp_ssn;
4509 FTP_DATA_SESSION *data_ssn = (FTP_DATA_SESSION *)
4510 _dpd.sessionAPI->get_application_data(p->stream_session, PP_FTPTELNET);
4511
4512 if (!PROTO_IS_FTP_DATA(data_ssn) || !FTPDataDirection(p, data_ssn))
4513 return;
4514
4515 ftp_ssn = (FTP_SESSION *) _dpd.sessionAPI->get_application_data_from_key(data_ssn->ftp_key, PP_FTPTELNET);
4516 initFilePosition(&data_ssn->position, _dpd.fileAPI->get_file_processed_size(p->stream_session));
4517 finalFilePosition(&data_ssn->position);
4518
4519 _dpd.streamAPI->request_flush_stream(p);
4520 if (ftp_ssn && (data_ssn->flags & FTPDATA_FLG_REST) && (ftp_ssn->rest_cmd_offset > 0))
4521 {
4522 File_Verdict verdict;
4523 verdict = _dpd.fileAPI->file_resume_block_check(p, data_ssn->path_hash);
4524 data_ssn->flags &= ~FTPDATA_FLG_REST;
4525 ftp_ssn->rest_cmd_offset = 0;
4526 if((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
4527 {
4528 _dpd.fileAPI->file_resume_block_add_file(p, data_ssn->path_hash, 0, 0, 0, NULL, ftp_ssn->control_clientPort,
4529 ftp_ssn->control_serverPort, true, data_ssn->direction);
4530 }
4531 return;
4532 }
4533
4534 if (!(data_ssn->flags & FTPDATA_FLG_STOP))
4535 {
4536 data_ssn->flags |= FTPDATA_FLG_STOP;
4537 FTPDataProcess(p, (FTP_DATA_SESSION *)_dpd.sessionAPI->get_application_data(p->stream_session, PP_FTPTELNET),
4538 (uint8_t *)p->payload,
4539 (uint16_t)p->payload_size);
4540 }
4541 }
4542
SnortFTPData_Flush(SFSnortPacket * p)4543 void SnortFTPData_Flush(SFSnortPacket *p)
4544 {
4545 FTP_DATA_SESSION *data_ssn = (FTP_DATA_SESSION *)
4546 _dpd.sessionAPI->get_application_data(p->stream_session, PP_FTPTELNET);
4547
4548 if (!PROTO_IS_FTP_DATA(data_ssn) || !FTPDataDirection(p, data_ssn))
4549 return;
4550
4551 initFilePosition(&data_ssn->position, _dpd.fileAPI->get_file_processed_size(p->stream_session));
4552 data_ssn->flags |= FTPDATA_FLG_FLUSH;
4553
4554 _dpd.streamAPI->request_flush_stream(p);
4555
4556 data_ssn->flags &= ~FTPDATA_FLG_FLUSH;
4557 return;
4558 }
4559
SnortFTPData(SFSnortPacket * p)4560 int SnortFTPData(SFSnortPacket *p)
4561 {
4562 FTP_SESSION *ftp_ssn;
4563 FTP_DATA_SESSION *data_ssn;
4564
4565 if (!p->stream_session)
4566 return -1;
4567
4568 data_ssn = (FTP_DATA_SESSION *)
4569 _dpd.sessionAPI->get_application_data(p->stream_session, PP_FTPTELNET);
4570
4571 if (!PROTO_IS_FTP_DATA(data_ssn))
4572 return -2;
4573
4574 if (data_ssn->flags & FTPDATA_FLG_STOP)
4575 return 0;
4576
4577 /* FTP-Data Session is in limbo, we need to lookup the control session
4578 * to figure out what to do. */
4579 ftp_ssn = (FTP_SESSION *) _dpd.sessionAPI->get_application_data_from_key(data_ssn->ftp_key, PP_FTPTELNET);
4580 if(!ftp_ssn)
4581 return -3;
4582
4583 #ifdef DAQ_PKT_FLAG_SSL_DETECTED
4584 // Set up the flow context when an SSL client hello is detected and
4585 // ignore packets until the flow is decrypted.
4586 if(p->pkt_header->flags & DAQ_PKT_FLAG_SSL_DETECTED)
4587 {
4588 ssl_callback_interface_t *ssl_cb;
4589 ssl_cb = (ssl_callback_interface_t *)_dpd.getSSLCallback();
4590 if(ssl_cb)
4591 {
4592 ftp_ssn->data_chan_state |= DATA_CHAN_CLIENT_HELLO_SEEN;
4593 ssl_cb->session_initialize(p, data_ssn, FTPData_Set_flow_id);
4594 }
4595 return 0; // Ignore SSL client hello.
4596 }
4597 else if(ftp_ssn->data_chan_state & DATA_CHAN_CLIENT_HELLO_SEEN)
4598 {
4599 if( _dpd.streamAPI->is_session_decrypted(p->stream_session))
4600 {
4601 // Done handling SSL handshake.
4602 ftp_ssn->data_chan_state &= ~DATA_CHAN_CLIENT_HELLO_SEEN;
4603 }
4604 else
4605 {
4606 return 0; // Ignore packet.
4607 }
4608 }
4609 #endif
4610 if ((data_ssn->flags & FTPDATA_FLG_REST) && (ftp_ssn->rest_cmd_offset > 0))
4611 {
4612 File_Verdict verdict;
4613 verdict = _dpd.fileAPI->file_resume_block_check(p, data_ssn->path_hash);
4614 data_ssn->flags &= ~FTPDATA_FLG_REST;
4615 ftp_ssn->rest_cmd_offset = 0;
4616 if((verdict == FILE_VERDICT_BLOCK) || (verdict == FILE_VERDICT_REJECT))
4617 {
4618 data_ssn->flags |= FTPDATA_FLG_STOP;
4619 _dpd.fileAPI->file_resume_block_add_file(p, data_ssn->path_hash, 0, 0, 0, NULL, ftp_ssn->control_clientPort,
4620 ftp_ssn->control_serverPort, true, data_ssn->direction);
4621 }
4622 return 0 ;
4623 }
4624 // bail if we have not rebuilt the stream yet.
4625 if (!_dpd.readyForProcess(p))
4626 return 0;
4627
4628 if (data_ssn->file_xfer_info == FTPP_FILE_UNKNOWN)
4629 {
4630 if (!PROTO_IS_FTP(ftp_ssn))
4631 {
4632 DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
4633 "FTP-DATA Invalid FTP_SESSION retrieved durring lookup\n"););
4634
4635 if (data_ssn->data_chan)
4636 _dpd.sessionAPI->set_ignore_direction(p->stream_session, SSN_DIR_BOTH);
4637
4638 return -2;
4639 }
4640
4641 switch (ftp_ssn->file_xfer_info)
4642 {
4643 case FTPP_FILE_UNKNOWN:
4644 /* Keep waiting */
4645 break;
4646
4647 case FTPP_FILE_IGNORE:
4648 /* This wasn't a file transfer; ignore it */
4649 if (data_ssn->data_chan)
4650 _dpd.sessionAPI->set_ignore_direction(p->stream_session, SSN_DIR_BOTH);
4651 return 0;
4652
4653 default:
4654 /* A file transfer was detected. */
4655 data_ssn->direction = ftp_ssn->data_xfer_dir;
4656 data_ssn->file_xfer_info = ftp_ssn->file_xfer_info;
4657 ftp_ssn->file_xfer_info = 0;
4658 data_ssn->filename = ftp_ssn->filename;
4659 ftp_ssn->filename = NULL;
4660 break;
4661 }
4662 }
4663
4664 if (!FTPDataDirection(p, data_ssn))
4665 return 0;
4666
4667 if (isFileEnd(data_ssn->position))
4668 {
4669 data_ssn->flags |= FTPDATA_FLG_STOP;
4670 }
4671 else
4672 {
4673 initFilePosition(&data_ssn->position,
4674 _dpd.fileAPI->get_file_processed_size(p->stream_session));
4675 if (p->tcp_header && (p->tcp_header->flags & TCPHEADER_FIN))
4676 finalFilePosition(&data_ssn->position);
4677 }
4678
4679 FTPDataProcess(p, data_ssn, (uint8_t *)p->payload, (uint16_t)p->payload_size);
4680 return 0;
4681 }
4682 #endif /* TARGET_BASED */
4683
FTPPBounceInit(struct _SnortConfig * sc,char * name,char * parameters,void ** dataPtr)4684 int FTPPBounceInit(struct _SnortConfig *sc, char *name, char *parameters, void **dataPtr)
4685 {
4686 char **toks;
4687 int num_toks;
4688
4689 toks = _dpd.tokenSplit(parameters, ",", 12, &num_toks, 0);
4690
4691 if(num_toks > 0)
4692 {
4693 DynamicPreprocessorFatalMessage("ERROR: Bad arguments to '%s' option: '%s'\n",
4694 name, parameters);
4695 }
4696
4697 _dpd.tokenFree(&toks, num_toks);
4698
4699 *dataPtr = NULL;
4700
4701 return 1;
4702 }
4703
4704
4705 /****************************************************************************
4706 *
4707 * Function: FTPPBounce(void *pkt, uint8_t **cursor, void **dataPtr)
4708 *
4709 * Purpose: Use this function to perform the particular detection routine
4710 * that this rule keyword is supposed to encompass.
4711 *
4712 * Arguments: p => pointer to the decoded packet
4713 * cursor => pointer to the current location in the buffer
4714 * dataPtr => pointer to rule specific data (not used for this option)
4715 *
4716 * Returns: If the detection test fails, this function *must* return a zero!
4717 * On success, it returns 1;
4718 *
4719 ****************************************************************************/
FTPPBounceEval(void * pkt,const uint8_t ** cursor,void * dataPtr)4720 int FTPPBounceEval(void *pkt, const uint8_t **cursor, void *dataPtr)
4721 {
4722 uint32_t ip = 0;
4723 SFSnortPacket *p = (SFSnortPacket *)pkt;
4724 int octet=0;
4725 const char *start_ptr, *end_ptr;
4726 const char *this_param = *(const char **)cursor;
4727
4728 int dsize;
4729
4730 if ( !p->ip4_header )
4731 return 0;
4732
4733 if(_dpd.Is_DetectFlag(SF_FLAG_ALT_DETECT))
4734 {
4735 dsize = _dpd.altDetect->len;
4736 start_ptr = (const char*) _dpd.altDetect->data;
4737 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4738 "Using Alternative Detect buffer!\n"););
4739 }
4740 else if(_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE))
4741 {
4742 dsize = _dpd.altBuffer->len;
4743 start_ptr = (const char *) _dpd.altBuffer->data;
4744 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4745 "Using Alternative Decode buffer!\n"););
4746
4747 }
4748 else
4749 {
4750 start_ptr = (const char *)p->payload;
4751 dsize = p->payload_size;
4752 }
4753
4754 DEBUG_WRAP(
4755 DebugMessage(DEBUG_PATTERN_MATCH,"[*] ftpbounce firing...\n");
4756 DebugMessage(DEBUG_PATTERN_MATCH,"payload starts at %p\n", start_ptr);
4757 ); /* END DEBUG_WRAP */
4758
4759 /* save off whatever our ending pointer is */
4760 end_ptr = start_ptr + dsize;
4761
4762 while ((this_param < end_ptr) && isspace((int)*this_param)) this_param++;
4763
4764 do
4765 {
4766 int value = 0;
4767
4768 do
4769 {
4770 if (!isdigit((int)*this_param))
4771 {
4772 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4773 "[*] ftpbounce non digit char failed..\n"););
4774 return RULE_NOMATCH;
4775 }
4776
4777 value = value * 10 + (*this_param - '0');
4778 this_param++;
4779
4780 } while ((this_param < end_ptr) &&
4781 (*this_param != ',') &&
4782 (!(isspace((int)*this_param))));
4783
4784 if (value > 0xFF)
4785 {
4786 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4787 "[*] ftpbounce value > 256 ..\n"););
4788 return RULE_NOMATCH;
4789 }
4790
4791 if (octet < 4)
4792 {
4793 ip = (ip << 8) + value;
4794 }
4795
4796 if ((this_param < end_ptr) && !isspace((int)*this_param))
4797 this_param++;
4798
4799 octet++;
4800
4801 } while ((this_param < end_ptr) && !isspace((int)*this_param) && (octet < 4));
4802
4803 if (octet < 4)
4804 {
4805 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4806 "[*] ftpbounce insufficient data ..\n"););
4807 return RULE_NOMATCH;
4808 }
4809
4810 if (ip != ntohl(p->ip4_header->source.s_addr))
4811 {
4812 /* Bounce attempt -- IPs not equal */
4813 return RULE_MATCH;
4814 }
4815 else
4816 {
4817 DEBUG_WRAP(DebugMessage(DEBUG_PATTERN_MATCH,
4818 "PORT command not being used in bounce\n"););
4819 return RULE_NOMATCH;
4820 }
4821
4822 /* Never reached */
4823 return RULE_NOMATCH;
4824 }
4825
4826 /* Add ports configured for ftptelnet preprocessor to stream5 port filtering so that
4827 * if any_any rules are being ignored then the packet still reaches ftptelnet.
4828 *
4829 * For ports in global_server configuration, server_lookup and server_lookupIpv6,
4830 * add the port to stream5 port filter list.
4831 */
_FTPTelnetAddPortsOfInterest(struct _SnortConfig * sc,FTPTELNET_GLOBAL_CONF * config,tSfPolicyId policy_id)4832 static void _FTPTelnetAddPortsOfInterest(struct _SnortConfig *sc, FTPTELNET_GLOBAL_CONF *config, tSfPolicyId policy_id)
4833 {
4834 int i;
4835
4836 if (config == NULL)
4837 return;
4838
4839 /* For the server callback */
4840 ftp_current_policy = policy_id;
4841
4842 _addPortsToStream(sc, config->telnet_config->proto_ports.ports, policy_id, 0);
4843 _addPortsToStream(sc, config->default_ftp_server->proto_ports.ports, policy_id, 1);
4844 ftpp_ui_server_iterate(sc, config->server_lookup,
4845 _addFtpServerConfPortsToStream, &i);
4846 }
4847
_addFtpServerConfPortsToStream(struct _SnortConfig * sc,void * pData)4848 static int _addFtpServerConfPortsToStream(struct _SnortConfig *sc, void *pData)
4849 {
4850 FTP_SERVER_PROTO_CONF *pConf = (FTP_SERVER_PROTO_CONF *)pData;
4851 _addPortsToStream(sc, pConf->proto_ports.ports, ftp_current_policy, 1);
4852 return 0;
4853 }
4854
4855 // flush at last line feed in payload
4856 // preproc will deal with any pipelined commands
ftp_paf(void * ssn,void ** pv,const uint8_t * data,uint32_t len,uint64_t * flags,uint32_t * fp,uint32_t * fp_eoh)4857 static PAF_Status ftp_paf (
4858 void* ssn, void** pv, const uint8_t* data, uint32_t len,
4859 uint64_t *flags, uint32_t* fp, uint32_t* fp_eoh)
4860 {
4861 #ifdef HAVE_MEMRCHR
4862 uint8_t* lf = memrchr(data, '\n', len);
4863 #else
4864 uint32_t n = len;
4865 uint8_t* lf = NULL, * tmp = (uint8_t*) data;
4866
4867 while ( (tmp = memchr(tmp, '\n', n)) )
4868 {
4869 lf = tmp++;
4870 n = len - (tmp - data);
4871 }
4872 #endif
4873
4874 DEBUG_WRAP(DebugMessage(DEBUG_STREAM_PAF,
4875 "%s[%d] '%*.*s'\n", __FUNCTION__, len, len, len, data));
4876
4877 if ( !lf )
4878 return PAF_SEARCH;
4879
4880 *fp = lf - data + 1;
4881 return PAF_FLUSH;
4882 }
4883
4884 #ifdef TARGET_BASED
_FTPTelnetAddService(struct _SnortConfig * sc,int16_t app,tSfPolicyId policy)4885 static void _FTPTelnetAddService (struct _SnortConfig *sc, int16_t app, tSfPolicyId policy)
4886 {
4887 if ( _dpd.isPafEnabled() )
4888 {
4889 ftp_paf_id = _dpd.streamAPI->register_paf_service(sc, policy, app, true, ftp_paf, true);
4890 ftp_paf_id = _dpd.streamAPI->register_paf_service(sc, policy, app, false, ftp_paf, true);
4891 }
4892 }
4893 #endif
4894
_addPortsToStream(struct _SnortConfig * sc,char * ports,tSfPolicyId policy_id,int ftp)4895 static void _addPortsToStream(struct _SnortConfig *sc, char *ports, tSfPolicyId policy_id, int ftp)
4896 {
4897 unsigned int i;
4898
4899 for (i = 0; i < MAXPORTS; i++)
4900 {
4901 if (ports[i])
4902 {
4903 //Add port the port
4904 _dpd.streamAPI->set_port_filter_status(sc, IPPROTO_TCP, (uint16_t)i,
4905 PORT_MONITOR_SESSION, policy_id, 1);
4906
4907 if ( ftp && _dpd.isPafEnabled() )
4908 {
4909 ftp_paf_id = _dpd.streamAPI->register_paf_port(sc, policy_id, (uint16_t)i, true, ftp_paf, false);
4910 ftp_paf_id = _dpd.streamAPI->register_paf_port(sc, policy_id, (uint16_t)i, false, ftp_paf, false);
4911 }
4912 }
4913 }
4914 }
4915
FtpTelnetInitGlobalConfig(FTPTELNET_GLOBAL_CONF * config,char * ErrorString,int iErrStrLen)4916 int FtpTelnetInitGlobalConfig(FTPTELNET_GLOBAL_CONF *config,
4917 char *ErrorString, int iErrStrLen)
4918 {
4919 int iRet;
4920
4921 if (config == NULL)
4922 {
4923 snprintf(ErrorString, iErrStrLen, "Global configuration is NULL.");
4924 return FTPP_FATAL_ERR;
4925 }
4926
4927 iRet = ftpp_ui_config_init_global_conf(config);
4928 if (iRet)
4929 {
4930 snprintf(ErrorString, iErrStrLen,
4931 "Error initializing Global Configuration.");
4932
4933 return FTPP_FATAL_ERR;
4934 }
4935
4936 return 0;
4937 }
4938
4939
FTP_Set_flow_id(void * app_data,uint32_t fid)4940 void FTP_Set_flow_id( void *app_data, uint32_t fid )
4941 {
4942 FTP_SESSION *ssn = (FTP_SESSION *)app_data;
4943 if( ssn )
4944 ssn->flow_id = fid;
4945 }
4946
FTPData_Set_flow_id(void * app_data,uint32_t fid)4947 void FTPData_Set_flow_id( void *app_data, uint32_t fid )
4948 {
4949 #ifdef TARGET_BASED
4950 FTP_DATA_SESSION *ssn = (FTP_DATA_SESSION *)app_data;
4951 if( ssn )
4952 ssn->flow_id = fid;
4953 #endif
4954 }
4955