I found a case where qpsmtpd-async detects the end of data marker
incorrectly: the previous packet did not end with CRLF and the current
packet starts with .CRLF. The code assumes that the previous packet
ended with CRLF.

Attached are a test script and a suggested patch.


Thanks,
Radu Greab

#!/usr/bin/perl -w

use strict;
use Net::SMTP;

my $smtp = Net::SMTP->new('localhost:25', Debug => 1);
$smtp->mail('');
$smtp->to('[EMAIL PROTECTED]');
$smtp->data;

$smtp->datasend("Subject: test\n\n");

$smtp->datasend('Chunk that does not end with CRLF');
sleep 1;  # let qpsmtpd get the data as a packet

$smtp->datasend(".\nAnother line that may get lost.\n");

$smtp->dataend;
$smtp->quit;
=== lib/Qpsmtpd/PollServer.pm
==================================================================
--- lib/Qpsmtpd/PollServer.pm   (revision 147)
+++ lib/Qpsmtpd/PollServer.pm   (local)
@@ -28,6 +28,7 @@
     _extras
     _test_mode
     _transaction
+    _prev_crlf          # did previous data chunk end with CRLF?
 );
 use Qpsmtpd::Constants;
 use Qpsmtpd::Address;
@@ -85,6 +86,7 @@
     };
     $self->{mode} = 'cmd';
     $self->{_extras} = {};
+    $self->{_prev_crlf} = 0;
 }
 
 sub respond {
@@ -229,10 +231,15 @@
 
     my $done = 0;
     my $remainder;
-    if ($data =~ s/^\.\r\n(.*)\z//ms) {
+    # end of data: either previous chunk ended with CRLF and
+    # current chunk starts with .CRLF or current chunk contains
+    # CRLF.CRLF
+    if (($self->{_prev_crlf} && $data =~ s/^\.\r\n(.*)\z//ms) ||
+        $data =~ s/\r\n\.\r\n(.*)\z/\r\n/ms) {
         $remainder = $1;
         $done = 1;
     }
+    $self->{_prev_crlf} = $data =~ /\r\n\z/;
 
     # add a transaction->blocked check back here when we have line by line 
plugin access...
     unless (($self->{max_size} and $self->{data_size} > $self->{max_size})) {

Reply via email to