From: Don P. <pm...@pi...> - 2007-01-16 19:21:31
|
Hi -- here's a bug found while I was trying to integrate a PMilter-based milter into Postfix (and a stomp for that bug). When Postfix accepts a message, part of its housekeeping routine after accepting a message is to send abort commands to milters (the Postfix logs indicate that it sends two abort commands to the milters after each message). However, PMilter doesn't currently check to see if it is processing a message when it receives an abort command from the MTA. The most noticeable side effect of this bug is after a message is received: [connect callback] > 220 example.com ESMTP Postfix < helo helo [helo callback] > 250 example.com < mail from: you [envfrom callback] > 250 2.1.0 Ok < rcpt to: root [envrcpt callback] > 250 2.1.5 Ok < data > 354 End data with... < (message headers and body here) < . [header, eoh, body, and eom callbacks] > 250 2.0.0 OK: queued as .... < quit [abort callback here, this should not happen] [close callback] > 221 2.0.0 Bye PMilter acts as advertised up to the point where the sender issues the QUIT (or RSET) command. At that time, Postfix cleans up after itself, sends aborts to the milters... which PMilter handles by calling the abort callback routine (twice!), which the Milter API says is not supposed to happen if the eom callback has been called. Looking at the libmilter source, the stock libmilter checks message state while processing an abort request, and will not call the abort callback if the milter is not processing a message -- i.e., before MAIL FROM or after the end of the message body is accepted. The end result is if I run Postfix with a milter based on libmilter and one based on PMilter, the libmilter-based one does not cough up the abort callback after QUIT, while the PMilter-based one does. (I have not verified this behavior with other MTAs; this is with Postfix 2.4-20070113 and earlier to 2.3.3.) Here's a patch against /pmilter/lib/Sendmail/PMilter/Context.pm v1.20 that should fix this problem -- with this patch applied, PMilter properly calls the abort callback only if a message is in progress (indicated by the presence of an envelope sender). > root@linux:/usr/local/share/perl/5.8.8/Sendmail/PMilter# diff -c Context-1.20.pm Context.pm > *** Context-1.20.pm 2007-01-16 12:41:58.000000000 -0600 > --- Context.pm 2007-01-16 12:54:02.000000000 -0600 > *************** > *** 44,50 **** > > use Sendmail::PMilter qw(:all); > > ! our $VERSION = '0.95_01'; > > # need documentation for this: > our $Map6to4 = 0; > --- 44,50 ---- > > use Sendmail::PMilter qw(:all); > > ! our $VERSION = '0.95_02'; > > # need documentation for this: > our $Map6to4 = 0; > *************** > *** 199,206 **** > $this->read_block(\$buf, $len - 1) || die "EOF in stream\n"; > > if ($cmd eq SMFIC_ABORT) { > delete $this->{symbols}{&SMFIC_MAIL}; > - $this->call_hooks('abort'); > } elsif ($cmd eq SMFIC_BODY) { > $this->call_hooks('body', $buf, length($buf)); > } elsif ($cmd eq SMFIC_CONNECT) { > --- 199,207 ---- > $this->read_block(\$buf, $len - 1) || die "EOF in stream\n"; > > if ($cmd eq SMFIC_ABORT) { > + # only call abort if we are in the middle of receiving a msg > + $this->call_hooks('abort') if exists $this->{symbols}{&SMFIC_MAIL}; > delete $this->{symbols}{&SMFIC_MAIL}; > } elsif ($cmd eq SMFIC_BODY) { > $this->call_hooks('body', $buf, length($buf)); > } elsif ($cmd eq SMFIC_CONNECT) { > *************** > *** 260,265 **** > --- 261,268 ---- > } elsif ($cmd eq SMFIC_BODYEOB) { > $this->call_hooks('body', $buf, length($buf)) if length($buf); > $this->call_hooks('eom'); > + # done with message, so throw away envelope sender > + delete $this->{symbols}{&SMFIC_MAIL} ; > } elsif ($cmd eq SMFIC_HELO) { > my $helo = &$split_buf; > die "SMFIC_HELO: bad packet\n" unless (@$helo == 1); Thanks! Don Piven spa...@pi... (unless you are a humanoid, in which case send replies to "don"). |