@@ -229,13 +229,13 @@ static inline void SMTPSetProgressTC(SMTPTransaction *tx, uint8_t progress)
229229{
230230 if (tx != NULL && tx -> progress_tc < progress ) {
231231 tx -> progress_tc = progress ;
232+ tx -> tx_data .updated_tc = true;
232233 }
233234}
234235
235- static bool SMTPTransactionIsComplete (const SMTPTransaction * tx )
236+ static bool SMTPTransactionRequestIsComplete (const SMTPTransaction * tx )
236237{
237- return tx && tx -> progress_ts == SMTP_REQUEST_COMPLETE &&
238- tx -> progress_tc == SMTP_RESPONSE_COMPLETE ;
238+ return tx && tx -> progress_ts == SMTP_REQUEST_COMPLETE ;
239239}
240240
241241typedef struct SMTPThreadCtx_ {
@@ -673,7 +673,8 @@ static AppLayerResult SMTPGetLine(Flow *f, StreamSlice *slice, SMTPState *state,
673673 }
674674}
675675
676- static int SMTPInsertCommandIntoCommandBuffer (uint8_t command , SMTPState * state )
676+ static int SMTPInsertCommandIntoCommandBuffer (
677+ SMTPState * state , uint8_t command , const SMTPTransaction * tx )
677678{
678679 SCEnter ();
679680 void * ptmp ;
@@ -688,12 +689,26 @@ static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state)
688689 sizeof (uint8_t ) * (state -> cmds_buffer_len + increment ));
689690 if (ptmp == NULL ) {
690691 SCFree (state -> cmds );
692+ SCFree (state -> cmds_tx_ids );
691693 state -> cmds = NULL ;
694+ state -> cmds_tx_ids = NULL ;
692695 SCLogDebug ("SCRealloc failure" );
693696 return -1 ;
694697 }
695698 state -> cmds = ptmp ;
696699
700+ ptmp = SCRealloc (
701+ state -> cmds_tx_ids , sizeof (uint64_t ) * (state -> cmds_buffer_len + increment ));
702+ if (ptmp == NULL ) {
703+ SCFree (state -> cmds );
704+ SCFree (state -> cmds_tx_ids );
705+ state -> cmds = NULL ;
706+ state -> cmds_tx_ids = NULL ;
707+ SCLogDebug ("SCRealloc failure" );
708+ return -1 ;
709+ }
710+ state -> cmds_tx_ids = ptmp ;
711+
697712 state -> cmds_buffer_len += increment ;
698713 }
699714 if (state -> cmds_cnt >= 1 &&
@@ -712,6 +727,7 @@ static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state)
712727 }
713728
714729 state -> cmds [state -> cmds_cnt ] = command ;
730+ state -> cmds_tx_ids [state -> cmds_cnt ] = tx != NULL ? tx -> tx_id : UINT64_MAX ;
715731 state -> cmds_cnt ++ ;
716732
717733 return 0 ;
@@ -766,29 +782,29 @@ static void SetMimeEvents(SMTPState *state, uint32_t events)
766782 }
767783}
768784
769- static inline void SMTPTransactionComplete (SMTPState * state )
785+ static inline void SMTPTransactionComplete (SMTPTransaction * tx )
770786{
771- DEBUG_VALIDATE_BUG_ON (state -> curr_tx == NULL );
772- if (state -> curr_tx ) {
773- SMTPSetProgressTS (state -> curr_tx , SMTP_REQUEST_COMPLETE );
774- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_COMPLETE );
787+ DEBUG_VALIDATE_BUG_ON (tx == NULL );
788+ if (tx ) {
789+ SMTPSetProgressTS (tx , SMTP_REQUEST_COMPLETE );
790+ SMTPSetProgressTC (tx , SMTP_RESPONSE_COMPLETE );
775791 }
776792}
777793
778- static inline void SMTPTransactionCompleteTS (SMTPState * state )
794+ static inline void SMTPTransactionCompleteTS (SMTPTransaction * tx )
779795{
780- DEBUG_VALIDATE_BUG_ON (state -> curr_tx == NULL );
781- if (state -> curr_tx ) {
782- SMTPSetProgressTS (state -> curr_tx , SMTP_REQUEST_COMPLETE );
796+ DEBUG_VALIDATE_BUG_ON (tx == NULL );
797+ if (tx ) {
798+ SMTPSetProgressTS (tx , SMTP_REQUEST_COMPLETE );
783799 SCLogDebug ("marked tx as ts complete" );
784800 }
785801}
786802
787- static inline void SMTPTransactionCompleteTC (SMTPState * state )
803+ static inline void SMTPTransactionCompleteTC (SMTPTransaction * tx )
788804{
789- DEBUG_VALIDATE_BUG_ON (state -> curr_tx == NULL );
790- if (state -> curr_tx ) {
791- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_COMPLETE );
805+ DEBUG_VALIDATE_BUG_ON (tx == NULL );
806+ if (tx ) {
807+ SMTPSetProgressTC (tx , SMTP_RESPONSE_COMPLETE );
792808 SCLogDebug ("marked tx as tc complete" );
793809 }
794810}
@@ -815,7 +831,7 @@ static int SMTPProcessCommandDATA(
815831 * acknowledged with a reply. We insert a dummy command to
816832 * the command buffer to be used by the reply handler to match
817833 * the reply received */
818- SMTPInsertCommandIntoCommandBuffer (SMTP_COMMAND_DATA_MODE , state );
834+ SMTPInsertCommandIntoCommandBuffer (state , SMTP_COMMAND_DATA_MODE , tx );
819835 if (smtp_config .raw_extraction ) {
820836 /* we use this as the signal that message data is complete. */
821837 FileCloseFile (& tx -> files_ts , & smtp_config .sbcfg , NULL , 0 , 0 );
@@ -827,7 +843,7 @@ static int SMTPProcessCommandDATA(
827843 FileFlowToFlags (f , STREAM_TOSERVER ));
828844 }
829845 }
830- SMTPTransactionCompleteTS (state );
846+ SMTPTransactionCompleteTS (tx );
831847 } else if (smtp_config .raw_extraction ) {
832848 // message not over, store the line. This is a substitution of
833849 // ProcessDataChunk
@@ -924,8 +940,31 @@ static int SMTPProcessCommandDATA(
924940
925941static inline bool IsReplyToCommand (const SMTPState * state , const uint8_t cmd )
926942{
927- return (state -> cmds_idx < state -> cmds_buffer_len &&
928- state -> cmds [state -> cmds_idx ] == cmd );
943+ return (state -> cmds_idx < state -> cmds_cnt && state -> cmds [state -> cmds_idx ] == cmd );
944+ }
945+
946+ static SMTPTransaction * SMTPStateGetTxById (SMTPState * state , uint64_t tx_id )
947+ {
948+ SMTPTransaction * tx = NULL ;
949+ TAILQ_FOREACH (tx , & state -> tx_list , next ) {
950+ if (tx -> tx_id == tx_id ) {
951+ return tx ;
952+ }
953+ if (tx -> tx_id > tx_id ) {
954+ break ;
955+ }
956+ }
957+ return NULL ;
958+ }
959+
960+ static SMTPTransaction * SMTPGetReplyTx (SMTPState * state )
961+ {
962+ if (state -> cmds_idx >= state -> cmds_cnt ) {
963+ return NULL ;
964+ }
965+
966+ SMTPTransaction * tx = SMTPStateGetTxById (state , state -> cmds_tx_ids [state -> cmds_idx ]);
967+ return tx != NULL ? tx : state -> curr_tx ;
929968}
930969
931970static int SMTPProcessReply (
@@ -938,8 +977,12 @@ static int SMTPProcessReply(
938977 return 0 ; // to continue processing further
939978 }
940979
941- if (state -> curr_tx ) {
942- state -> curr_tx -> tx_data .updated_tc = true;
980+ SMTPTransaction * reply_tx = SMTPGetReplyTx (state );
981+ if (reply_tx == NULL ) {
982+ reply_tx = state -> curr_tx ;
983+ }
984+ if (reply_tx != NULL ) {
985+ reply_tx -> tx_data .updated_tc = true;
943986 }
944987 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
945988 * reply code */
@@ -1010,16 +1053,16 @@ static int SMTPProcessReply(
10101053 if (!SCAppLayerRequestProtocolTLSUpgrade (f )) {
10111054 SMTPSetEvent (state , SMTP_DECODER_EVENT_FAILED_PROTOCOL_CHANGE );
10121055 }
1013- if (state -> curr_tx ) {
1014- SMTPTransactionComplete (state );
1056+ if (reply_tx ) {
1057+ SMTPTransactionComplete (reply_tx );
10151058 }
10161059 } else {
10171060 /* decoder event */
10181061 SMTPSetEvent (state , SMTP_DECODER_EVENT_TLS_REJECTED );
10191062 }
10201063 } else if (IsReplyToCommand (state , SMTP_COMMAND_DATA )) {
10211064 if (reply_code == SMTP_REPLY_354 ) {
1022- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_DATA );
1065+ SMTPSetProgressTC (reply_tx , SMTP_RESPONSE_DATA );
10231066 /* Next comes the mail for the DATA command in toserver direction */
10241067 state -> parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE ;
10251068 } else {
@@ -1031,15 +1074,15 @@ static int SMTPProcessReply(
10311074 SMTPSetEvent (state , SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED );
10321075 }
10331076 } else if (IsReplyToCommand (state , SMTP_COMMAND_BDAT )) {
1034- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_DATA );
1077+ SMTPSetProgressTC (reply_tx , SMTP_RESPONSE_DATA );
10351078 } else if (IsReplyToCommand (state , SMTP_COMMAND_DATA_MODE )) {
10361079 if (!(state -> parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY )) {
1037- SMTPTransactionCompleteTC (state );
1080+ SMTPTransactionCompleteTC (reply_tx );
10381081 }
10391082 } else if (IsReplyToCommand (state , SMTP_COMMAND_RSET )) {
1040- if (reply_code == SMTP_REPLY_250 && state -> curr_tx &&
1083+ if (reply_code == SMTP_REPLY_250 && reply_tx &&
10411084 !(state -> parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY )) {
1042- SMTPTransactionComplete (state );
1085+ SMTPTransactionComplete (reply_tx );
10431086 }
10441087 } else {
10451088 /* we don't care for any other command for now */
@@ -1238,7 +1281,7 @@ static int SMTPProcessRequest(
12381281 return 0 ;
12391282 }
12401283 if (state -> curr_tx == NULL ||
1241- (SMTPTransactionIsComplete (state -> curr_tx ) && !NoNewTx (state , line ))) {
1284+ (SMTPTransactionRequestIsComplete (state -> curr_tx ) && !NoNewTx (state , line ))) {
12421285 tx = SMTPTransactionCreate (state );
12431286 if (tx == NULL )
12441287 return -1 ;
@@ -1344,7 +1387,7 @@ static int SMTPProcessRequest(
13441387
13451388 /* Every command is inserted into a command buffer, to be matched
13461389 * against reply(ies) sent by the server */
1347- if (SMTPInsertCommandIntoCommandBuffer (state -> current_command , state ) == -1 ) {
1390+ if (SMTPInsertCommandIntoCommandBuffer (state , state -> current_command , tx ) == -1 ) {
13481391 SCReturnInt (-1 );
13491392 }
13501393
@@ -1594,6 +1637,12 @@ void *SMTPStateAlloc(void *orig_state, AppProto proto_orig)
15941637 SCFree (smtp_state );
15951638 return NULL ;
15961639 }
1640+ smtp_state -> cmds_tx_ids = SCMalloc (sizeof (uint64_t ) * SMTP_COMMAND_BUFFER_STEPS );
1641+ if (smtp_state -> cmds_tx_ids == NULL ) {
1642+ SCFree (smtp_state -> cmds );
1643+ SCFree (smtp_state );
1644+ return NULL ;
1645+ }
15971646 smtp_state -> cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS ;
15981647
15991648 TAILQ_INIT (& smtp_state -> tx_list );
@@ -1691,6 +1740,9 @@ static void SMTPStateFree(void *p)
16911740 if (smtp_state -> cmds != NULL ) {
16921741 SCFree (smtp_state -> cmds );
16931742 }
1743+ if (smtp_state -> cmds_tx_ids != NULL ) {
1744+ SCFree (smtp_state -> cmds_tx_ids );
1745+ }
16941746
16951747 if (smtp_state -> helo ) {
16961748 SCFree (smtp_state -> helo );
@@ -4341,6 +4393,7 @@ static int SMTPParserTest14(void)
43414393 StreamTcpFreeConfig (true);
43424394 return result ;
43434395}
4396+
43444397#endif /* UNITTESTS */
43454398
43464399void SMTPParserRegisterTests (void )
0 commit comments