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