--- src/smtp_in.c.orig 2003-12-13 11:34:50.000000000 +0000 +++ src/smtp_in.c 2003-12-13 12:08:56.000000000 +0000 @@ -194,6 +194,12 @@ static int smtp_had_eof; static int smtp_had_error; +/* The following variables get used to make sure that we don't give out protocol +errors to data which the client couldn't have known failed based on it choosing +to pipeline them.*/ +static BOOL smtp_pkt_boundary = TRUE; +static int smtp_pkt_mail_count = 0; +static int smtp_pkt_rcpt_count = 0; /************************************************* * SMTP version of getc() * @@ -502,6 +508,19 @@ if (hadnull) return BADCHAR_CMD; +/* If we set a boundary last time, then reset our counters for what's in +this pipelining packet.*/ + +if(smtp_pkt_boundary==TRUE) { + smtp_pkt_boundary=FALSE; + smtp_pkt_mail_count=0; + smtp_pkt_rcpt_count=0; +} + +if(smtp_inptr == smtp_inend) { + smtp_pkt_boundary=TRUE; +} + /* Scan command list and return identity, having set the data pointer to the start of the actual data characters. Check for SMTP synchronization if required. */ @@ -2479,6 +2498,7 @@ it is the canonical extracted address which is all that is kept. */ case MAIL_CMD: + smtp_pkt_mail_count++; /* Count to keep track of client pipeline */ smtp_mailcmd_count++; /* Count for limit and ratelimit */ if (helo_required && !helo_seen) @@ -2765,14 +2785,24 @@ extracted address. */ case RCPT_CMD: + smtp_pkt_rcpt_count++; /* keep track of client pipelining */ rcpt_count++; if (sender_address == NULL) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, - US"sender not yet given"); - rcpt_fail_count++; - break; + if(smtp_pkt_mail_count) + { + smtp_printf("503 sender not yet given\r\n"); + rcpt_fail_count++; + break; + } + else + { + done = synprot_error(L_smtp_protocol_error, 503, NULL, + US"sender not yet given"); + rcpt_fail_count++; + break; + } } if (smtp_data[0] == 0) @@ -2918,21 +2948,39 @@ /* The DATA command is legal only if it follows successful MAIL FROM and RCPT TO commands. This function is complete when a valid DATA - command is encountered. */ + command is encountered. However, we must make sure that we don't + penalise clients that can't tell that previous commands failed because + they pipelined everything. */ case DATA_CMD: if (sender_address == NULL) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, - US"MAIL command must precede DATA"); - break; + if(smtp_pkt_mail_count) + { + smtp_printf("554 No valid senders\r\n"); + break; + } + else + { + done = synprot_error(L_smtp_protocol_error, 503, NULL, + US"MAIL command must precede DATA"); + break; + } } if (!discarded && recipients_count <= 0) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, - US"valid RCPT command must precede DATA"); - break; + if(smtp_pkt_rcpt_count) + { + smtp_printf("554 No valid recipients\r\n"); + break; + } + else + { + done = synprot_error(L_smtp_protocol_error, 503, NULL, + US"valid RCPT command must precede DATA"); + break; + } } if (toomany && recipients_max_reject)