@ -1,4 +1,4 @@
/* Copyright (C) 2007-202 0 Open Information Security Foundation
/* Copyright (C) 2007-202 2 Open Information Security Foundation
*
* You can copy , redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -57,6 +57,7 @@
# include "util-memrchr.h"
# include "util-mem.h"
# include "util-misc.h"
# include "util-validate.h"
# include "output-json.h"
# include "rust.h"
@ -125,6 +126,7 @@ const FtpCommand FtpCommands[FTP_COMMAND_MAX + 1] = {
{ FTP_COMMAND_UNKNOWN , NULL , 0 }
} ;
uint64_t ftp_config_memcap = 0 ;
uint32_t ftp_max_line_len = 4096 ;
SC_ATOMIC_DECLARE ( uint64_t , ftp_memuse ) ;
SC_ATOMIC_DECLARE ( uint64_t , ftp_memcap ) ;
@ -152,6 +154,14 @@ static void FTPParseMemcap(void)
SC_ATOMIC_INIT ( ftp_memuse ) ;
SC_ATOMIC_INIT ( ftp_memcap ) ;
if ( ( ConfGet ( " app-layer.protocols.ftp.max-line-length " , & conf_val ) ) = = 1 ) {
if ( ParseSizeStringU32 ( conf_val , & ftp_max_line_len ) < 0 ) {
SCLogError ( SC_ERR_SIZE_PARSE , " Error parsing ftp.max-line-length from conf file - %s. " ,
conf_val ) ;
}
SCLogConfig ( " FTP max line length: % " PRIu32 , ftp_max_line_len ) ;
}
}
static void FTPIncrMemuse ( uint64_t size )
@ -350,6 +360,7 @@ static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
/* we have seen the lf for the previous line. Clear the parser
* details to parse new line */
line_state - > current_line_lf_seen = 0 ;
state - > current_line_truncated = false ;
if ( line_state - > current_line_db = = 1 ) {
line_state - > current_line_db = 0 ;
FTPFree ( line_state - > db , line_state - > db_len ) ;
@ -377,20 +388,27 @@ static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
line_state - > current_line_db = 1 ;
memcpy ( line_state - > db , state - > input , state - > input_len ) ;
line_state - > db_len = state - > input_len ;
} else {
ptmp = FTPRealloc ( line_state - > db , line_state - > db_len ,
( line_state - > db_len + state - > input_len ) ) ;
if ( ptmp = = NULL ) {
FTPFree ( line_state - > db , line_state - > db_len ) ;
line_state - > db = NULL ;
line_state - > db_len = 0 ;
return - 1 ;
} else if ( ! state - > current_line_truncated ) {
int32_t input_len = state - > input_len ;
if ( line_state - > db_len + input_len > ftp_max_line_len ) {
input_len = ftp_max_line_len - line_state - > db_len ;
DEBUG_VALIDATE_BUG_ON ( input_len < 0 ) ;
state - > current_line_truncated = true ;
}
line_state - > db = ptmp ;
if ( input_len > 0 ) {
ptmp = FTPRealloc (
line_state - > db , line_state - > db_len , ( line_state - > db_len + input_len ) ) ;
if ( ptmp = = NULL ) {
FTPFree ( line_state - > db , line_state - > db_len ) ;
line_state - > db = NULL ;
line_state - > db_len = 0 ;
return - 1 ;
}
line_state - > db = ptmp ;
memcpy ( line_state - > db + line_state - > db_len ,
state - > input , state - > input_len ) ;
line_state - > db_len + = state - > input_len ;
memcpy ( line_state - > db + line_state - > db_len , state - > input , input_len ) ;
line_state - > db_len + = input_len ;
}
}
state - > input + = state - > input_len ;
state - > input_len = 0 ;
@ -401,27 +419,35 @@ static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
line_state - > current_line_lf_seen = 1 ;
if ( line_state - > current_line_db = = 1 ) {
ptmp = FTPRealloc ( line_state - > db , line_state - > db_len ,
( line_state - > db_len + ( lf_idx + 1 - state - > input ) ) ) ;
if ( ptmp = = NULL ) {
FTPFree ( line_state - > db , line_state - > db_len ) ;
line_state - > db = NULL ;
line_state - > db_len = 0 ;
return - 1 ;
}
line_state - > db = ptmp ;
if ( ! state - > current_line_truncated ) {
int32_t input_len = lf_idx + 1 - state - > input ;
if ( line_state - > db_len + input_len > ftp_max_line_len ) {
input_len = ftp_max_line_len - line_state - > db_len ;
DEBUG_VALIDATE_BUG_ON ( input_len < 0 ) ;
state - > current_line_truncated = true ;
}
if ( input_len > 0 ) {
ptmp = FTPRealloc (
line_state - > db , line_state - > db_len , ( line_state - > db_len + input_len ) ) ;
if ( ptmp = = NULL ) {
FTPFree ( line_state - > db , line_state - > db_len ) ;
line_state - > db = NULL ;
line_state - > db_len = 0 ;
return - 1 ;
}
line_state - > db = ptmp ;
memcpy ( line_state - > db + line_state - > db_len ,
state - > input , ( lf_idx + 1 - state - > input ) ) ;
line_state - > db_len + = ( lf_idx + 1 - state - > input ) ;
memcpy ( line_state - > db + line_state - > db_len , state - > input , input_len ) ;
line_state - > db_len + = input_len ;
if ( line_state - > db_len > 1 & &
line_state - > db [ line_state - > db_len - 2 ] = = 0x0D ) {
line_state - > db_len - = 2 ;
state - > current_line_delimiter_len = 2 ;
} else {
line_state - > db_len - = 1 ;
state - > current_line_delimiter_len = 1 ;
if ( line_state - > db_len > 1 & & line_state - > db [ line_state - > db_len - 2 ] = = 0x0D ) {
line_state - > db_len - = 2 ;
state - > current_line_delimiter_len = 2 ;
} else {
line_state - > db_len - = 1 ;
state - > current_line_delimiter_len = 1 ;
}
}
}
state - > current_line = line_state - > db ;
@ -429,7 +455,12 @@ static int FTPGetLineForDirection(FtpState *state, FtpLineState *line_state)
} else {
state - > current_line = state - > input ;
state - > current_line_len = lf_idx - state - > input ;
if ( lf_idx - state - > input > ftp_max_line_len ) {
state - > current_line_len = ftp_max_line_len ;
state - > current_line_truncated = true ;
} else {
state - > current_line_len = lf_idx - state - > input ;
}
if ( state - > input ! = lf_idx & &
* ( lf_idx - 1 ) = = 0x0D ) {
@ -591,6 +622,7 @@ static AppLayerResult FTPParseRequest(Flow *f, void *ftp_state,
tx - > command_descriptor = cmd_descriptor ;
tx - > request_length = CopyCommandLine ( & tx - > request ,
state - > current_line , state - > current_line_len ) ;
tx - > request_truncated = state - > current_line_truncated ;
/* change direction (default to server) so expectation will handle
* the correct message when expectation will match .
@ -813,6 +845,7 @@ static AppLayerResult FTPParseResponse(Flow *f, void *ftp_state, AppLayerParserS
FTPString * response = FTPStringAlloc ( ) ;
if ( likely ( response ) ) {
response - > len = CopyCommandLine ( & response - > str , state - > current_line , state - > current_line_len ) ;
response - > truncated = state - > current_line_truncated ;
TAILQ_INSERT_TAIL ( & tx - > response_list , response , next ) ;
}
}