develooper Front page | perl.cvs.qpsmtpd | Postings from April 2006

[svn:qpsmtpd] r631 - in branches/0.3x: . config.sample lib/Apache lib/Qpsmtpd plugins t

From:
jpeacock
Date:
April 7, 2006 11:58
Subject:
[svn:qpsmtpd] r631 - in branches/0.3x: . config.sample lib/Apache lib/Qpsmtpd plugins t
Message ID:
20060407185803.831B9CBA47@x12.develooper.com
Author: jpeacock
Date: Fri Apr  7 11:58:02 2006
New Revision: 631

Added:
   branches/0.3x/lib/Qpsmtpd/Command.pm
   branches/0.3x/plugins/dont_require_anglebrackets
   branches/0.3x/plugins/parse_addr_withhelo
Modified:
   branches/0.3x/Changes
   branches/0.3x/MANIFEST
   branches/0.3x/config.sample/plugins
   branches/0.3x/lib/Apache/Qpsmtpd.pm
   branches/0.3x/lib/Qpsmtpd/Plugin.pm
   branches/0.3x/lib/Qpsmtpd/SMTP.pm
   branches/0.3x/lib/Qpsmtpd/SelectServer.pm
   branches/0.3x/lib/Qpsmtpd/TcpServer.pm
   branches/0.3x/plugins/check_badmailfrom
   branches/0.3x/plugins/check_badmailfromto
   branches/0.3x/plugins/check_badrcptto
   branches/0.3x/plugins/dns_whitelist_soft
   branches/0.3x/plugins/dnsbl
   branches/0.3x/plugins/milter
   branches/0.3x/plugins/rcpt_ok
   branches/0.3x/plugins/require_resolvable_fromhost
   branches/0.3x/plugins/rhsbl
   branches/0.3x/plugins/sender_permitted_from
   branches/0.3x/t/addresses.t

Log:
Add Qpsmtpd::Command to gather all parsing logic in one place (Hanno
Hecker)


Modified: branches/0.3x/Changes
==============================================================================
--- branches/0.3x/Changes	(original)
+++ branches/0.3x/Changes	Fri Apr  7 11:58:02 2006
@@ -1,12 +1,15 @@
 0.33
 
-   Fix a spurious newline at the start of messages queued via exim (Devin
-   Carraway)
+  Add Qpsmtpd::Command to gather all parsing logic in one place (Hanno
+  Hecker)
 
-   Make the clamdscan plugin temporarily deny mail if if can't talk to clamd
-   (Filippo Carletti)
+  Fix a spurious newline at the start of messages queued via exim (Devin
+  Carraway)
 
-   Improve Qpsmtpd::Transaction documentation (Fred Moyer)
+  Make the clamdscan plugin temporarily deny mail if if can't talk to clamd
+  (Filippo Carletti)
+
+  Improve Qpsmtpd::Transaction documentation (Fred Moyer)
 
 
 0.32 - 2006/02/26

Modified: branches/0.3x/MANIFEST
==============================================================================
--- branches/0.3x/MANIFEST	(original)
+++ branches/0.3x/MANIFEST	Fri Apr  7 11:58:02 2006
@@ -16,6 +16,7 @@
 lib/Qpsmtpd.pm
 lib/Qpsmtpd/Address.pm
 lib/Qpsmtpd/Auth.pm
+lib/Qpsmtpd/Command.pm
 lib/Qpsmtpd/Connection.pm
 lib/Qpsmtpd/Constants.pm
 lib/Qpsmtpd/Plugin.pm

Modified: branches/0.3x/config.sample/plugins
==============================================================================
--- branches/0.3x/config.sample/plugins	(original)
+++ branches/0.3x/config.sample/plugins	Fri Apr  7 11:58:02 2006
@@ -12,6 +12,13 @@
 # from one IP!
 hosts_allow
 
+# enable to accept MAIL FROM:/RCPT TO: addresses without surrounding <>
+dont_require_anglebrackets
+
+# enable to reject MAIL FROM:/RCPT TO: parameters if client helo was HELO
+# (strict RFC 821)... this is not used in EHLO ...
+# parse_addr_withhelo
+
 quit_fortune
 
 check_earlytalker

Modified: branches/0.3x/lib/Apache/Qpsmtpd.pm
==============================================================================
--- branches/0.3x/lib/Apache/Qpsmtpd.pm	(original)
+++ branches/0.3x/lib/Apache/Qpsmtpd.pm	Fri Apr  7 11:58:02 2006
@@ -131,7 +131,7 @@
     while (defined(my $data = $self->getline)) {
         $data =~ s/\r?\n$//s; # advanced chomp
         $self->log(LOGDEBUG, "dispatching $data");
-        defined $self->dispatch(split / +/, $data)
+        defined $self->dispatch(split / +/, $data, 2)
             or $self->respond(502, "command unrecognized: '$data'");
         last if $self->{_quitting};
     }

Added: branches/0.3x/lib/Qpsmtpd/Command.pm
==============================================================================
--- (empty file)
+++ branches/0.3x/lib/Qpsmtpd/Command.pm	Fri Apr  7 11:58:02 2006
@@ -0,0 +1,170 @@
+package Qpsmtpd::Command;
+
+=head1 NAME
+
+Qpsmtpd::Command - parse arguments to SMTP commands
+
+=head1 DESCRIPTION
+
+B<Qpsmtpd::Command> provides just one public sub routine: B<parse()>.
+
+This sub expects two or three arguments. The first is the name of the 
+SMTP command (such as I<HELO>, I<MAIL>, ...). The second must be the remaining
+of the line the client sent.
+
+If no third argument is given (or it's not a reference to a CODE) it parses 
+the line according to RFC 1869 (SMTP Service Extensions) for the I<MAIL> and 
+I<RCPT> commands and splitting by spaces (" ") for all other.
+
+Any module can supply it's own parsing routine by returning a sub routine 
+reference from a hook_*_parse. This sub will be called with I<$self>, I<$cmd>
+and I<$line>. 
+
+On successfull parsing it MUST return B<OK> (the constant from 
+I<Qpsmtpd::Constants>) success as first argument and a list of 
+values, which will be the arguments to the hook for this command.
+
+If parsing failed, the second returned value (if any) will be returned to the
+client as error message.
+
+=head1 EXAMPLE
+
+Inside a plugin 
+
+ sub hook_unrecognized_command_parse {
+    my ($self, $transaction, $cmd) = @_;
+    return (OK, \&bdat_parser) if ($cmd eq 'bdat');
+ }
+ 
+ sub bdat_parser {
+    my ($self,$cmd,$line) = @_;
+    # .. do something with $line...
+    return (DENY, "Invalid arguments") 
+      if $some_reason_why_there_is_a_syntax_error;
+    return (OK, @args);
+ }
+ 
+ sub hook_unrecognized_command {
+    my ($self, $transaction, $cmd, @args) = @_;
+    return (DECLINED) if ($self->qp->connection->hello eq 'helo');
+    return (DECLINED) unless ($cmd eq 'bdat');
+    ....
+ }
+
+=cut
+
+use Qpsmtpd::Constants;
+use vars qw(@ISA);
+@ISA = qw(Qpsmtpd::SMTP);
+use strict;
+
+sub parse {
+    my ($me,$cmd,$line,$sub) = @_;
+    return (OK) unless defined $line; # trivial case
+    my $self = {};
+    bless $self, $me;
+    $cmd = lc $1;
+    if ($sub and (ref($sub) eq 'CODE')) {
+        my @ret = eval { $sub->($self, $cmd, $line); };
+        if ($@) {
+            $self->log(LOGERROR, "Failed to parse command [$cmd]: $@");
+            return (DENY, $line, ());
+        }
+        ## my @log = @ret;
+        ## for (@log) {
+        ##     $_ ||= "";
+        ## }
+        ## $self->log(LOGDEBUG, "parse($cmd) => [".join("], [", @log)."]");
+        return @ret;
+    } 
+    my $parse = "parse_$cmd";
+    if ($self->can($parse)) {
+        # print "CMD=$cmd,line=$line\n";
+        my @out = eval { $self->$parse($cmd, $line); };
+        if ($@) {
+            $self->log(LOGERROR, "$parse($cmd,$line) failed: $@");
+            return(DENY, "Failed to parse line");
+        }
+        return @out;
+    }
+    return(OK, split(/ +/, $line)); # default :)
+}
+
+sub parse_rcpt {
+    my ($self,$cmd,$line) = @_;
+    return (DENY, "Syntax error in command") unless $line =~ s/^to:\s*//i;
+    return &_get_mail_params($cmd, $line);
+}
+
+sub parse_mail {
+    my ($self,$cmd,$line) = @_;
+    return (DENY, "Syntax error in command") unless $line =~ s/^from:\s*//i;
+    return &_get_mail_params($cmd, $line);
+}
+### RFC 1869:
+## 6.  MAIL FROM and RCPT TO Parameters
+## [...]
+##
+##   esmtp-cmd        ::= inner-esmtp-cmd [SP esmtp-parameters] CR LF
+##   esmtp-parameters ::= esmtp-parameter *(SP esmtp-parameter)
+##   esmtp-parameter  ::= esmtp-keyword ["=" esmtp-value]
+##   esmtp-keyword    ::= (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
+##
+##                        ; syntax and values depend on esmtp-keyword
+##   esmtp-value      ::= 1*<any CHAR excluding "=", SP, and all
+##                           control characters (US ASCII 0-31
+##                           inclusive)>
+##
+##                        ; The following commands are extended to
+##                        ; accept extended parameters.
+##   inner-esmtp-cmd  ::= ("MAIL FROM:" reverse-path)   /
+##                        ("RCPT TO:" forward-path)
+sub _get_mail_params {
+    my ($cmd,$line) = @_;
+    my @params = ();
+    $line =~ s/\s*$//;
+
+    while ($line =~ s/\s+([A-Za-z0-9][A-Za-z0-9\-]*(=[^= \x00-\x1f]+)?)$//) {
+        push @params, $1;
+    }
+    @params = reverse @params;
+
+    # the above will "fail" (i.e. all of the line in @params) on 
+    # some addresses without <> like
+    #    MAIL FROM: user=name@example.net
+    # or RCPT TO: postmaster
+
+    # let's see if $line contains nothing and use the first value as address:
+    if ($line) {
+        # parameter syntax error, i.e. not all of the arguments were 
+        # stripped by the while() loop:
+        return (DENY, "Syntax error in parameters")
+          if ($line =~ /\@.*\s/); 
+        return (OK, $line, @params);
+    }
+
+    $line = shift @params; 
+    if ($cmd eq "mail") {
+        return (OK, "<>") unless $line; # 'MAIL FROM:' --> 'MAIL FROM:<>'
+        return (DENY, "Syntax error in parameters") 
+          if ($line =~ /\@.*\s/); # parameter syntax error
+    }
+    else {
+        if ($line =~ /\@/) {
+            return (DENY, "Syntax error in parameters") 
+              if ($line =~ /\@.*\s/);
+        } 
+        else {
+            # XXX: what about 'abuse' in Qpsmtpd::Address?
+            return (DENY, "Syntax error in parameters") if $line =~ /\s/;
+            return (DENY, "Syntax error in address") 
+              unless ($line =~ /^(postmaster|abuse)$/i); 
+        }
+    }
+    ## XXX:  No: let this do a plugin, so it's not up to us to decide
+    ##       if we require <> around an address :-)
+    ## unless ($line =~ /^<.*>$/) { $line = "<".$line.">"; }
+    return (OK, $line, @params);
+}
+
+1;

Modified: branches/0.3x/lib/Qpsmtpd/Plugin.pm
==============================================================================
--- branches/0.3x/lib/Qpsmtpd/Plugin.pm	(original)
+++ branches/0.3x/lib/Qpsmtpd/Plugin.pm	Fri Apr  7 11:58:02 2006
@@ -4,9 +4,10 @@
 
 # more or less in the order they will fire
 our @hooks = qw(
-    logging config pre-connection connect ehlo helo
-    auth auth-plain auth-login auth-cram-md5
-    rcpt mail data data_post queue_pre queue queue_post
+    logging config pre-connection connect ehlo_parse ehlo
+    helo_parse helo auth_parse auth auth-plain auth-login auth-cram-md5
+    rcpt_parse rcpt_pre rcpt mail_parse mail mail_pre 
+    data data_post queue_pre queue queue_post
     quit reset_transaction disconnect post-connection
     unrecognized_command deny ok
 );

Modified: branches/0.3x/lib/Qpsmtpd/SMTP.pm
==============================================================================
--- branches/0.3x/lib/Qpsmtpd/SMTP.pm	(original)
+++ branches/0.3x/lib/Qpsmtpd/SMTP.pm	Fri Apr  7 11:58:02 2006
@@ -12,6 +12,7 @@
 use Qpsmtpd::Constants;
 use Qpsmtpd::Auth;
 use Qpsmtpd::Address ();
+use Qpsmtpd::Command;
 
 use Mail::Header ();
 #use Data::Dumper;
@@ -143,13 +144,16 @@
 
 
 sub helo {
-  my ($self, $hello_host, @stuff) = @_;
+  my ($self, $line) = @_;
+  my ($rc, @msg) = $self->run_hooks('helo_parse');
+  my ($ok, $hello_host, @stuff) = Qpsmtpd::Command->parse('helo', $line, $msg[0]);
+
   return $self->respond (501,
     "helo requires domain/address - see RFC-2821 4.1.1.1") unless $hello_host;
   my $conn = $self->connection;
   return $self->respond (503, "but you already said HELO ...") if $conn->hello;
 
-  my ($rc, @msg) = $self->run_hooks("helo", $hello_host, @stuff);
+  ($rc, @msg) = $self->run_hooks("helo", $hello_host, @stuff);
   if ($rc == DONE) {
     # do nothing
   } elsif ($rc == DENY) {
@@ -171,13 +175,15 @@
 }
 
 sub ehlo {
-  my ($self, $hello_host, @stuff) = @_;
+  my ($self, $line) = @_;
+  my ($rc, @msg) = $self->run_hooks('ehlo_parse');
+  my ($ok, $hello_host, @stuff) = Qpsmtpd::Command->parse('ehlo', $line, $msg[0]);
   return $self->respond (501,
     "ehlo requires domain/address - see RFC-2821 4.1.1.1") unless $hello_host;
   my $conn = $self->connection;
   return $self->respond (503, "but you already said HELO ...") if $conn->hello;
 
-  my ($rc, @msg) = $self->run_hooks("ehlo", $hello_host, @stuff);
+  ($rc, @msg) = $self->run_hooks("ehlo", $hello_host, @stuff);
   if ($rc == DONE) {
     # do nothing
   } elsif ($rc == DENY) {
@@ -229,7 +235,12 @@
 }
 
 sub auth {
-    my ( $self, $arg, @stuff ) = @_;
+    my ($self, $line) = @_;
+    my ($rc, $sub)    = $self->run_hooks('auth_parse');
+    my ($ok, $arg, @stuff) = Qpsmtpd::Command->parse('auth', $line, $sub);
+    return $self->respond(501, $arg || "Syntax error in command") 
+      unless ($ok == OK);
+    
 
     #they AUTH'd once already
     return $self->respond( 503, "but you already said AUTH ..." )
@@ -242,9 +253,7 @@
 }
 
 sub mail {
-  my $self = shift;
-  return $self->respond(501, "syntax error in parameters") if !$_[0] or $_[0] !~ m/^from:/i;
-
+  my ($self, $line) = @_;
   # -> from RFC2821
   # The MAIL command (or the obsolete SEND, SOML, or SAML commands)
   # begins a mail transaction.  Once started, a mail transaction
@@ -269,16 +278,29 @@
     return $self->respond(503, "please say hello first ...");
   }
   else {
-    my $from_parameter = join " ", @_;
-    $self->log(LOGINFO, "full from_parameter: $from_parameter");
-
-    my ($from) = ($from_parameter =~ m/^from:\s*(<[^>]*>)/i)[0];
-
-    # support addresses without <> ... maybe we shouldn't?
-    ($from) = "<" . ($from_parameter =~ m/^from:\s*(\S+)/i)[0] . ">"
-      unless $from;
+    $self->log(LOGINFO, "full from_parameter: $line");
+    my ($rc, @msg) = $self->run_hooks("mail_parse");
+    my ($ok, $from, @params) = Qpsmtpd::Command->parse('mail', $line, $msg[0]);
+    return $self->respond(501, $from || "Syntax error in command") 
+      unless ($ok == OK); 
+    my %param;
+    foreach (@params) {
+        my ($k,$v) = split /=/, $_, 2;
+        $param{lc $k} = $v;
+    }
+    # to support addresses without <> we now require a plugin
+    # hooking "mail_pre" to 
+    #   return (OK, "<$from>"); 
+    # (...or anything else parseable by Qpsmtpd::Address ;-))
+    # see also comment in sub rcpt()
+    ($rc, @msg) = $self->run_hooks("mail_pre", $from);
+    if ($rc == OK) {
+      $from = shift @msg;
+    }
 
     $self->log(LOGALERT, "from email address : [$from]");
+    return $self->respond(501, "could not parse your mail from command") 
+      unless $from =~ /^<.*>$/;
 
     if ($from eq "<>" or $from =~ m/\[undefined\]/ or $from eq "<#@[]>") {
       $from = Qpsmtpd::Address->new("<>");
@@ -288,7 +310,7 @@
     }
     return $self->respond(501, "could not parse your mail from command") unless $from;
 
-    my ($rc, @msg) = $self->run_hooks("mail", $from);
+    ($rc, @msg) = $self->run_hooks("mail", $from, %param);
     if ($rc == DONE) {
       return 1;
     }
@@ -323,18 +345,39 @@
 }
 
 sub rcpt {
-  my $self = shift;
-  return $self->respond(501, "syntax error in parameters") unless $_[0] and $_[0] =~ m/^to:/i;
+  my ($self, $line) = @_;
+  my ($rc, @msg)    = $self->run_hooks("rcpt_parse");
+  my ($ok, $rcpt, @param) = Qpsmtpd::Command->parse("rcpt", $line, $msg[0]);
+  return $self->respond(501, $rcpt || "Syntax error in command")
+    unless ($ok == OK);
   return $self->respond(503, "Use MAIL before RCPT") unless $self->transaction->sender;
 
-  my ($rcpt) = ($_[0] =~ m/to:(.*)/i)[0];
-  $rcpt = $_[1] unless $rcpt;
+  my %param;
+  foreach (@param) {
+    my ($k,$v) = split /=/, $_, 2;
+    $param{lc $k} = $v;
+  }
+  # to support addresses without <> we now require a plugin
+  # hooking "rcpt_pre" to 
+  #   return (OK, "<$rcpt>"); 
+  # (... or anything else parseable by Qpsmtpd::Address ;-))
+  # this means, a plugin can decide to (pre-)accept
+  # addresses like <user@example.com.> or <user@example.com >
+  # by removing the trailing "."/" " from this example...
+  ($rc, @msg) = $self->run_hooks("rcpt_pre", $rcpt);
+  if ($rc == OK) {
+    $rcpt = shift @msg;
+  }
   $self->log(LOGALERT, "to email address : [$rcpt]");
+  return $self->respond(501, "could not parse recipient") 
+    unless $rcpt =~ /^<.*>$/;
+
   $rcpt = (Qpsmtpd::Address->parse($rcpt))[0];
 
-  return $self->respond(501, "could not parse recipient") unless $rcpt;
+  return $self->respond(501, "could not parse recipient") 
+    if (!$rcpt or ($rcpt->format eq '<>'));
 
-  my ($rc, @msg) = $self->run_hooks("rcpt", $rcpt);
+  ($rc, @msg) = $self->run_hooks("rcpt", $rcpt, %param);
   if ($rc == DONE) {
     return 1;
   }

Modified: branches/0.3x/lib/Qpsmtpd/SelectServer.pm
==============================================================================
--- branches/0.3x/lib/Qpsmtpd/SelectServer.pm	(original)
+++ branches/0.3x/lib/Qpsmtpd/SelectServer.pm	Fri Apr  7 11:58:02 2006
@@ -121,7 +121,7 @@
                 }
                 else {
                     $qp->log(LOGINFO, "dispatching $req");
-                    defined $qp->dispatch(split / +/, $req)
+                    defined $qp->dispatch(split / +/, $req, 2)
                         or $qp->respond(502, "command unrecognized: '$req'");
                 }
             }

Modified: branches/0.3x/lib/Qpsmtpd/TcpServer.pm
==============================================================================
--- branches/0.3x/lib/Qpsmtpd/TcpServer.pm	(original)
+++ branches/0.3x/lib/Qpsmtpd/TcpServer.pm	Fri Apr  7 11:58:02 2006
@@ -63,7 +63,7 @@
     $_ =~ s/\r?\n$//s; # advanced chomp
     $self->log(LOGDEBUG, "dispatching $_");
     $self->connection->notes('original_string', $_);
-    defined $self->dispatch(split / +/, $_)
+    defined $self->dispatch(split / +/, $_, 2)
       or $self->respond(502, "command unrecognized: '$_'");
     alarm $timeout;
   }

Modified: branches/0.3x/plugins/check_badmailfrom
==============================================================================
--- branches/0.3x/plugins/check_badmailfrom	(original)
+++ branches/0.3x/plugins/check_badmailfrom	Fri Apr  7 11:58:02 2006
@@ -21,7 +21,7 @@
 =cut
 
 sub hook_mail {
-  my ($self, $transaction, $sender) = @_;
+  my ($self, $transaction, $sender, %param) = @_;
 
   my @badmailfrom = $self->qp->config("badmailfrom")
     or return (DECLINED);
@@ -44,7 +44,7 @@
 }
 
 sub hook_rcpt {
-  my ($self, $transaction, $rcpt) = @_;
+  my ($self, $transaction, $rcpt, %param) = @_;
   my $note = $transaction->notes('badmailfrom');
   if ($note) {
     $self->log(LOGINFO, $note);

Modified: branches/0.3x/plugins/check_badmailfromto
==============================================================================
--- branches/0.3x/plugins/check_badmailfromto	(original)
+++ branches/0.3x/plugins/check_badmailfromto	Fri Apr  7 11:58:02 2006
@@ -17,7 +17,7 @@
 =cut
 
 sub hook_mail {
-  my ($self, $transaction, $sender) = @_;
+  my ($self, $transaction, $sender, %param) = @_;
 
   my @badmailfromto = $self->qp->config("badmailfromto")
     or return (DECLINED);
@@ -41,7 +41,7 @@
 }
 
 sub hook_rcpt {
-  my ($self, $transaction, $rcpt) = @_;
+  my ($self, $transaction, $rcpt, %param) = @_;
   my $recipient = lc($rcpt->user) . '@' . lc($rcpt->host);
   my $sender = $transaction->notes('badmailfromto');
   if ($sender) {

Modified: branches/0.3x/plugins/check_badrcptto
==============================================================================
--- branches/0.3x/plugins/check_badrcptto	(original)
+++ branches/0.3x/plugins/check_badrcptto	Fri Apr  7 11:58:02 2006
@@ -2,7 +2,7 @@
 use Qpsmtpd::DSN;
 
 sub hook_rcpt {
-  my ($self, $transaction, $recipient) = @_;
+  my ($self, $transaction, $recipient, %param) = @_;
   my @badrcptto = $self->qp->config("badrcptto") or return (DECLINED);
   return (DECLINED) unless $recipient->host && $recipient->user;
   my $host = lc $recipient->host;

Modified: branches/0.3x/plugins/dns_whitelist_soft
==============================================================================
--- branches/0.3x/plugins/dns_whitelist_soft	(original)
+++ branches/0.3x/plugins/dns_whitelist_soft	Fri Apr  7 11:58:02 2006
@@ -139,7 +139,7 @@
 }
 
 sub hook_rcpt {
-  my ($self, $transaction, $rcpt) = @_;
+  my ($self, $transaction, $rcpt, %param) = @_;
   my $ip = $self->qp->connection->remote_ip || return (DECLINED);
   my $note = $self->process_sockets;
   if ( $note ) {

Modified: branches/0.3x/plugins/dnsbl
==============================================================================
--- branches/0.3x/plugins/dnsbl	(original)
+++ branches/0.3x/plugins/dnsbl	Fri Apr  7 11:58:02 2006
@@ -167,7 +167,7 @@
 }
 
 sub hook_rcpt {
-  my ($self, $transaction, $rcpt) = @_;
+  my ($self, $transaction, $rcpt, %param) = @_;
   my $connection = $self->qp->connection;
 
   # RBLSMTPD being non-empty means it contains the failure message to return

Added: branches/0.3x/plugins/dont_require_anglebrackets
==============================================================================
--- (empty file)
+++ branches/0.3x/plugins/dont_require_anglebrackets	Fri Apr  7 11:58:02 2006
@@ -0,0 +1,19 @@
+# 
+# dont_require_anglebrackets - accept addresses in MAIL FROM:/RCPT TO: 
+#        commands without surrounding <>
+#
+sub hook_mail_pre {
+    my ($self,$transaction, $addr) = @_;
+    unless ($addr =~ /^<.*>$/) {
+        $addr = "<".$addr.">";
+    }
+    return (OK, $addr);
+}
+
+sub hook_rcpt_pre {
+    my ($self,$transaction, $addr) = @_;
+    unless ($addr =~ /^<.*>$/) {
+        $addr = "<".$addr.">";
+    }
+    return (OK, $addr);
+}

Modified: branches/0.3x/plugins/milter
==============================================================================
--- branches/0.3x/plugins/milter	(original)
+++ branches/0.3x/plugins/milter	Fri Apr  7 11:58:02 2006
@@ -135,7 +135,7 @@
 }
 
 sub hook_mail {
-    my ($self, $transaction, $address) = @_;
+    my ($self, $transaction, $address, %param) = @_;
     
     my $milter = $self->qp->connection->notes('milter');
 
@@ -148,7 +148,7 @@
 }
 
 sub hook_rcpt {
-    my ($self, $transaction, $address) = @_;
+    my ($self, $transaction, $address, %param) = @_;
     
     my $milter = $self->qp->connection->notes('milter');
 

Added: branches/0.3x/plugins/parse_addr_withhelo
==============================================================================
--- (empty file)
+++ branches/0.3x/plugins/parse_addr_withhelo	Fri Apr  7 11:58:02 2006
@@ -0,0 +1,60 @@
+# parse_addr_withhelo
+# 
+# strict RFC 821 forbids parameters after the 
+#   MAIL FROM:<user@example.net> 
+# and
+#   RCPT TO:<someone@example.com>
+# 
+# load this plugin to enforce, else the default EHLO parsing with 
+# parameters is done.
+#
+
+sub hook_mail_parse {
+    my $self = shift;
+    return (OK, \&_parse) if ($self->qp->connection->hello eq 'helo');
+    return (DECLINED);
+}
+
+sub hook_rcpt_parse {
+    my $self = shift;
+    return (OK, \&_parse) if ($self->qp->connection->hello eq 'helo');
+    return (DECLINED);
+}
+
+sub _parse {
+    my ($self,$cmd,$line) = @_;
+    $self->log(LOGDEBUG, "_parse() cmd=[$cmd], line=[$line]");
+    if ($cmd eq 'mail') {
+        return(DENY, "Syntax error in command")
+          unless ($line =~ s/^from:\s*//i);
+    }
+    else { # cmd eq 'rcpt'
+        return(DENY, "Syntax error in command")
+          unless ($line =~ s/^to:\s*//i);
+    }
+
+    if ($line =~ s/^(<.*>)\s*//) {
+        my $addr = $1;
+        return (DENY, "No parameters allowed in ".uc($cmd))
+          if ($line =~ /^\S/);
+        return (OK, $addr, ());
+    }
+
+    ## now, no <> are given
+    $line =~ s/\s*$//;
+    if ($line =~ /\@/) {
+        return (DENY, "No parameters allowed in ".uc($cmd))
+          if ($line =~ /\@\S+\s+\S/);
+        return (OK, $line, ());
+    }
+
+    if ($cmd eq "mail") {
+        return (OK, "<>") unless $line; # 'MAIL FROM:' -> 'MAIL FROM:<>'
+        return (DENY, "Could not parse your MAIL FROM command");
+    }
+    else {
+        return (DENY, "Could not parse your RCPT TO command")
+          unless $line =~ /^(postmaster|abuse)$/i;
+    }
+}
+

Modified: branches/0.3x/plugins/rcpt_ok
==============================================================================
--- branches/0.3x/plugins/rcpt_ok	(original)
+++ branches/0.3x/plugins/rcpt_ok	Fri Apr  7 11:58:02 2006
@@ -5,7 +5,7 @@
 use Qpsmtpd::DSN;
 
 sub hook_rcpt {
-  my ($self, $transaction, $recipient) = @_;
+  my ($self, $transaction, $recipient, %param) = @_;
   my $host = lc $recipient->host;
 
   my @rcpt_hosts = ($self->qp->config("me"), $self->qp->config("rcpthosts"));

Modified: branches/0.3x/plugins/require_resolvable_fromhost
==============================================================================
--- branches/0.3x/plugins/require_resolvable_fromhost	(original)
+++ branches/0.3x/plugins/require_resolvable_fromhost	Fri Apr  7 11:58:02 2006
@@ -5,7 +5,7 @@
 my %invalid = ();
 
 sub hook_mail {
-  my ($self, $transaction, $sender) = @_;
+  my ($self, $transaction, $sender, %param) = @_;
 
   return DECLINED
         if ($self->qp->connection->notes('whitelistclient'));

Modified: branches/0.3x/plugins/rhsbl
==============================================================================
--- branches/0.3x/plugins/rhsbl	(original)
+++ branches/0.3x/plugins/rhsbl	Fri Apr  7 11:58:02 2006
@@ -1,14 +1,14 @@
 
 
 sub hook_mail {
-  my ($self, $transaction, $sender) = @_;
+  my ($self, $transaction, $sender, %param) = @_;
 
   my $res = new Net::DNS::Resolver;
   my $sel = IO::Select->new();
   my %rhsbl_zones_map = ();
 
-  # Perform any RHS lookups in the background. We just send the query packets here
-  # and pick up any results in the RCPT handler.
+  # Perform any RHS lookups in the background. We just send the query packets
+  # here and pick up any results in the RCPT handler.
   # MTAs gets confused when you reject mail during MAIL FROM:
 
     my %rhsbl_zones = map { (split /\s+/, $_, 2)[0,1] } $self->qp->config('rhsbl_zones');

Modified: branches/0.3x/plugins/sender_permitted_from
==============================================================================
--- branches/0.3x/plugins/sender_permitted_from	(original)
+++ branches/0.3x/plugins/sender_permitted_from	Fri Apr  7 11:58:02 2006
@@ -34,7 +34,7 @@
 }
 
 sub hook_mail {
-  my ($self, $transaction, $sender) = @_;
+  my ($self, $transaction, $sender, %param) = @_;
 
   return (DECLINED) unless ($sender->format ne "<>"
                             and $sender->host && $sender->user);
@@ -71,7 +71,7 @@
 }
 
 sub hook_rcpt {
-  my ($self, $transaction, $rcpt) = @_;
+  my ($self, $transaction, $rcpt, %param) = @_;
   
   # special addresses don't get SPF-tested.
   return DECLINED if $rcpt and $rcpt->user and $rcpt->user =~ /^(?:postmaster|abuse|mailer-daemon|root)$/i;

Modified: branches/0.3x/t/addresses.t
==============================================================================
--- branches/0.3x/t/addresses.t	(original)
+++ branches/0.3x/t/addresses.t	Fri Apr  7 11:58:02 2006
@@ -27,4 +27,11 @@
 is(($smtpd->command($command))[0], 250, $command);
 is($smtpd->transaction->sender->format, '<ask@p.qpsmtpd-test.askask.com>', 'got the right sender');
 
+$command = 'MAIL FROM:<ask@perl.org> SIZE=1230 CORRECT-WITHOUT-ARG';
+is(($smtpd->command($command))[0], 250, $command);
+
+$command = 'MAIL FROM:';
+is(($smtpd->command($command))[0], 250, $command);
+is($smtpd->transaction->sender->format, '<>', 'got the right sender');
+
 



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About