9595/* All other commands are represented by this var */
9696#define SMTP_COMMAND_OTHER_CMD 5
9797#define SMTP_COMMAND_RSET 6
98+ /* Like SMTP_COMMAND_BDAT, but the chunk was flagged LAST, so the server
99+ * reply matched to this command is the final verdict for the
100+ * transaction */
101+ #define SMTP_COMMAND_BDAT_LAST 7
98102
99103#define SMTP_DEFAULT_MAX_TX 256
100104
@@ -906,6 +910,21 @@ static inline bool IsReplyToCommand(const SMTPState *state, const uint8_t cmd)
906910 state -> cmds [state -> cmds_idx ] == cmd );
907911}
908912
913+ /* Get the transaction that a DATA/BDAT related server reply applies
914+ * to: the oldest transaction that has completed on the request side
915+ * but has not yet seen its response side completed. Falls back to the
916+ * current transaction, which is the common case. */
917+ static SMTPTransaction * SMTPGetReplyTx (SMTPState * state )
918+ {
919+ SMTPTransaction * tx ;
920+ TAILQ_FOREACH (tx , & state -> tx_list , next ) {
921+ if (tx -> done && tx -> progress_tc < SMTP_RESPONSE_COMPLETE ) {
922+ return tx ;
923+ }
924+ }
925+ return state -> curr_tx ;
926+ }
927+
909928static int SMTPProcessReply (
910929 SMTPState * state , Flow * f , SMTPThreadCtx * td , SMTPInput * input , const SMTPLine * line )
911930{
@@ -990,14 +1009,15 @@ static int SMTPProcessReply(
9901009 }
9911010 if (state -> curr_tx ) {
9921011 SMTPTransactionComplete (state );
1012+ SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_COMPLETE );
9931013 }
9941014 } else {
9951015 /* decoder event */
9961016 SMTPSetEvent (state , SMTP_DECODER_EVENT_TLS_REJECTED );
9971017 }
9981018 } else if (IsReplyToCommand (state , SMTP_COMMAND_DATA )) {
9991019 if (reply_code == SMTP_REPLY_354 ) {
1000- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_DATA );
1020+ SMTPSetProgressTC (SMTPGetReplyTx ( state ) , SMTP_RESPONSE_DATA );
10011021 /* Next comes the mail for the DATA command in toserver direction */
10021022 state -> parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE ;
10031023 } else {
@@ -1009,11 +1029,32 @@ static int SMTPProcessReply(
10091029 SMTPSetEvent (state , SMTP_DECODER_EVENT_DATA_COMMAND_REJECTED );
10101030 }
10111031 } else if (IsReplyToCommand (state , SMTP_COMMAND_BDAT )) {
1012- SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_DATA );
1032+ SMTPSetProgressTC (SMTPGetReplyTx (state ), SMTP_RESPONSE_DATA );
1033+ } else if (IsReplyToCommand (state , SMTP_COMMAND_BDAT_LAST )) {
1034+ /* the reply to the BDAT LAST chunk is the server's verdict on
1035+ * the transaction */
1036+ if (!(state -> parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY )) {
1037+ SMTPTransaction * reply_tx = SMTPGetReplyTx (state );
1038+ if (reply_tx != NULL ) {
1039+ reply_tx -> tx_data .updated_tc = true;
1040+ SMTPSetProgressTC (reply_tx , SMTP_RESPONSE_COMPLETE );
1041+ }
1042+ }
1043+ } else if (IsReplyToCommand (state , SMTP_COMMAND_DATA_MODE )) {
1044+ /* the reply to the mail data is the server's verdict on the
1045+ * transaction */
1046+ if (!(state -> parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY )) {
1047+ SMTPTransaction * reply_tx = SMTPGetReplyTx (state );
1048+ if (reply_tx != NULL ) {
1049+ reply_tx -> tx_data .updated_tc = true;
1050+ SMTPSetProgressTC (reply_tx , SMTP_RESPONSE_COMPLETE );
1051+ }
1052+ }
10131053 } else if (IsReplyToCommand (state , SMTP_COMMAND_RSET )) {
10141054 if (reply_code == SMTP_REPLY_250 && state -> curr_tx &&
10151055 !(state -> parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY )) {
10161056 SMTPTransactionComplete (state );
1057+ SMTPSetProgressTC (state -> curr_tx , SMTP_RESPONSE_COMPLETE );
10171058 }
10181059 } else {
10191060 /* we don't care for any other command for now */
@@ -1308,7 +1349,11 @@ static int SMTPProcessRequest(
13081349 if (r == -1 ) {
13091350 SCReturnInt (-1 );
13101351 }
1311- state -> current_command = SMTP_COMMAND_BDAT ;
1352+ if (state -> bdat_last ) {
1353+ state -> current_command = SMTP_COMMAND_BDAT_LAST ;
1354+ } else {
1355+ state -> current_command = SMTP_COMMAND_BDAT ;
1356+ }
13121357 SMTPSetProgressTS (tx , SMTP_REQUEST_DATA );
13131358 if (state -> bdat_chunk_len == 0 ) {
13141359 state -> parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE ;
@@ -1360,6 +1405,7 @@ static int SMTPProcessRequest(
13601405 return SMTPProcessCommandDATA (state , tx , f , line );
13611406
13621407 case SMTP_COMMAND_BDAT :
1408+ case SMTP_COMMAND_BDAT_LAST :
13631409 return SMTPProcessCommandBDAT (state , line );
13641410
13651411 default :
@@ -1496,7 +1542,8 @@ static AppLayerResult SMTPParse(uint8_t direction, Flow *f, SMTPState *state,
14961542 /* toserver */
14971543 if (direction == 0 ) {
14981544 if (((state -> current_command == SMTP_COMMAND_DATA ) ||
1499- (state -> current_command == SMTP_COMMAND_BDAT )) &&
1545+ (state -> current_command == SMTP_COMMAND_BDAT ) ||
1546+ (state -> current_command == SMTP_COMMAND_BDAT_LAST )) &&
15001547 (state -> parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE )) {
15011548 int ret = SMTPPreProcessCommands (state , f , & stream_slice , & input , & line );
15021549 DEBUG_VALIDATE_BUG_ON (ret != 0 && ret != -1 && ret != 1 );
@@ -1896,7 +1943,7 @@ static int SMTPStateGetAlstateProgress(void *vtx, uint8_t direction)
18961943 SMTPTransaction * tx = vtx ;
18971944 if (direction & STREAM_TOSERVER )
18981945 return tx -> done ? SMTP_REQUEST_COMPLETE : tx -> progress_ts ;
1899- return tx -> done ? SMTP_RESPONSE_COMPLETE : tx -> progress_tc ;
1946+ return tx -> progress_tc ;
19001947}
19011948
19021949static AppLayerGetFileState SMTPGetTxFiles (void * txv , uint8_t direction )
0 commit comments