@@ -526,7 +526,20 @@ static void SMTPSetEvent(SMTPState *s, uint8_t e)
526526 SCLogDebug ("couldn't set event %u" , e );
527527}
528528
529- static SMTPTransaction * SMTPTransactionCreate (SMTPState * state )
529+ static uint8_t * SMTPCopyParam (const uint8_t * src , uint16_t len )
530+ {
531+ uint8_t * copy = SCMalloc (len + 1 );
532+ if (copy == NULL ) {
533+ return NULL ;
534+ }
535+ if (len > 0 ) {
536+ memcpy (copy , src , len );
537+ }
538+ copy [len ] = '\0' ;
539+ return copy ;
540+ }
541+
542+ static SMTPTransaction * SMTPTransactionCreate (SMTPState * state , bool inherit_helo )
530543{
531544 if (state -> tx_cnt > smtp_config .max_tx ) {
532545 return NULL ;
@@ -538,6 +551,14 @@ static SMTPTransaction *SMTPTransactionCreate(SMTPState *state)
538551
539552 TAILQ_INIT (& tx -> rcpt_to_list );
540553 tx -> tx_data .file_tx = STREAM_TOSERVER ; // can xfer files
554+ if (inherit_helo && state -> helo != NULL ) {
555+ tx -> helo = SMTPCopyParam (state -> helo , state -> helo_len );
556+ if (tx -> helo == NULL ) {
557+ SCFree (tx );
558+ return NULL ;
559+ }
560+ tx -> helo_len = state -> helo_len ;
561+ }
541562 return tx ;
542563}
543564
@@ -1140,11 +1161,24 @@ static int SMTPParseCommandWithParam(SMTPState *state, const SMTPLine *line, uin
11401161
11411162static int SMTPParseCommandHELO (SMTPState * state , const SMTPLine * line )
11421163{
1143- if (state -> helo ) {
1164+ if (state -> curr_tx -> helo ) {
11441165 SMTPSetEvent (state , SMTP_DECODER_EVENT_DUPLICATE_FIELDS );
11451166 return 0 ;
11461167 }
1147- return SMTPParseCommandWithParam (state , line , 4 , & state -> helo , & state -> helo_len );
1168+ int r = SMTPParseCommandWithParam (
1169+ state , line , 4 , & state -> curr_tx -> helo , & state -> curr_tx -> helo_len );
1170+ if (r == 0 ) {
1171+ uint8_t * helo = SMTPCopyParam (state -> curr_tx -> helo , state -> curr_tx -> helo_len );
1172+ if (helo == NULL ) {
1173+ return -1 ;
1174+ }
1175+ if (state -> helo ) {
1176+ SCFree (state -> helo );
1177+ }
1178+ state -> helo = helo ;
1179+ state -> helo_len = state -> curr_tx -> helo_len ;
1180+ }
1181+ return r ;
11481182}
11491183
11501184static int SMTPParseCommandMAILFROM (SMTPState * state , const SMTPLine * line )
@@ -1178,6 +1212,12 @@ static int SMTPParseCommandRCPTTO(SMTPState *state, const SMTPLine *line)
11781212 return 0 ;
11791213}
11801214
1215+ static bool SMTPLineIsHelo (const SMTPLine * line )
1216+ {
1217+ return line -> len >= 4 && (SCMemcmpLowercase ("helo" , line -> buf , 4 ) == 0 ||
1218+ SCMemcmpLowercase ("ehlo" , line -> buf , 4 ) == 0 );
1219+ }
1220+
11811221/* consider 'rset' and 'quit' to be part of the existing state */
11821222static int NoNewTx (SMTPState * state , const SMTPLine * line )
11831223{
@@ -1235,9 +1275,15 @@ static int SMTPProcessRequest(
12351275 if (line -> len == 0 && line -> delim_len == 0 ) {
12361276 return 0 ;
12371277 }
1238- if (state -> curr_tx == NULL ||
1278+ const bool command_mode = !(state -> parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE );
1279+ const bool helo_cmd = command_mode && SMTPLineIsHelo (line );
1280+ const bool subsequent_helo = helo_cmd && state -> seen_helo ;
1281+ if (subsequent_helo && state -> curr_tx != NULL && !SMTPTransactionIsComplete (state -> curr_tx )) {
1282+ SMTPTransactionComplete (state );
1283+ }
1284+ if (state -> curr_tx == NULL || subsequent_helo ||
12391285 (SMTPTransactionIsComplete (state -> curr_tx ) && !NoNewTx (state , line ))) {
1240- tx = SMTPTransactionCreate (state );
1286+ tx = SMTPTransactionCreate (state , ! subsequent_helo );
12411287 if (tx == NULL )
12421288 return -1 ;
12431289 state -> curr_tx = tx ;
@@ -1313,12 +1359,12 @@ static int SMTPProcessRequest(
13131359 state -> current_command = SMTP_COMMAND_BDAT ;
13141360 SMTPSetProgressTS (tx , SMTP_REQUEST_DATA );
13151361 state -> parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE ;
1316- } else if (line -> len >= 4 && ((SCMemcmpLowercase ("helo" , line -> buf , 4 ) == 0 ) ||
1317- SCMemcmpLowercase ("ehlo" , line -> buf , 4 ) == 0 )) {
1362+ } else if (helo_cmd ) {
13181363 r = SMTPParseCommandHELO (state , line );
13191364 if (r == -1 ) {
13201365 SCReturnInt (-1 );
13211366 }
1367+ state -> seen_helo = true;
13221368 state -> current_command = SMTP_COMMAND_OTHER_CMD ;
13231369 } else if (line -> len >= 9 && SCMemcmpLowercase ("mail from" , line -> buf , 9 ) == 0 ) {
13241370 r = SMTPParseCommandMAILFROM (state , line );
@@ -1665,6 +1711,10 @@ static void SMTPTransactionFree(SMTPTransaction *tx, SMTPState *state)
16651711
16661712 SCAppLayerTxDataCleanup (& tx -> tx_data );
16671713
1714+ if (tx -> helo ) {
1715+ SCFree (tx -> helo );
1716+ }
1717+
16681718 if (tx -> mail_from )
16691719 SCFree (tx -> mail_from );
16701720
@@ -4121,8 +4171,10 @@ static int SMTPParserTest14(void)
41214171 goto end ;
41224172 }
41234173
4124- if ((smtp_state -> helo_len != 7 ) || strncmp ("boo.com" , (char * )smtp_state -> helo , 7 )) {
4125- printf ("incorrect parsing of HELO field '%s' (%d)\n" , smtp_state -> helo , smtp_state -> helo_len );
4174+ if ((smtp_state -> curr_tx -> helo_len != 7 ) ||
4175+ strncmp ("boo.com" , (char * )smtp_state -> curr_tx -> helo , 7 )) {
4176+ printf ("incorrect parsing of HELO field '%s' (%d)\n" , smtp_state -> curr_tx -> helo ,
4177+ smtp_state -> curr_tx -> helo_len );
41264178 goto end ;
41274179 }
41284180
@@ -4352,6 +4404,7 @@ static int SMTPParserTest14(void)
43524404 StreamTcpFreeConfig (true);
43534405 return result ;
43544406}
4407+
43554408#endif /* UNITTESTS */
43564409
43574410void SMTPParserRegisterTests (void )
0 commit comments