> 1: Why call the first one in the rcpt chain at all? Just make it a 
> connect plugin.

I could do this, and in fact i have attached an modified version of
'check_relay' which just does that. As it has otherwise the complete
same functionality as 'check_relay', you might think about replacing
the stock 'check_relay' with my version.

There seems to be one problem though (i think i remember we had this 
already as a topic some time ago): It seems that a transaction->relaying 
set in a connect plugin got lost by the time the rcpt plugins is 
called. Currently the usual workaround in code (e.g. also done in the SMTP
AUTH Handler) is to set $ENV{RELAYCLIENT} instead. 

I think i already suggested adding a connection->relaying flag, which
value is copied to transaction->relaying when a new transaction is startet.
This would allow us to get rid of using $ENV{RELAYCLIENT} as a flag, we
just should set it right before calling a queue plugin.

However i've added my 'check_relay' version for now.


-kju

-- 
      It's an insane world, but i'm proud to be a part of it. -- Bill Hicks
#
# check_relay
#
# this is an modified version of the the stock version of 'check_relay'.
#
# At connect time it will check $ENV{RELAYCLIENT} and the 'relayclients'
# and 'morerelayclients' config files to see if relaying is allowed for
# this client. If this it the case, the plugin will set the relaying
# flag in transaction. It will return DECLINED in any case. The idea
# here is to have this knowledge available early, so blocking lists
# like dnsbl could ignore this client.
#
# At rcpt time it will check if relaying is allowed for this client by
# checking the relaying flag in transaction (which could also be set
# for example by the smtp auth code) and for legacy reasons also
# $ENV{RELAYCLIENT} again. If this is found not to be an relaying user,
# we next check 'rcpthosts' and 'morercpthosts' to see, if we accept
# mail for the recipient domain.
#
# This plugin should be the last in the rcpt-chain, the position in
# the connect-chain usually does not matter.
#

sub register {
  my ($self, $qp) = @_;
  $self->register_hook("connect", "check_relay_connect");
  $self->register_hook("rcpt",    "check_relay_rcpt");
}

sub check_relay_connect {
  my ($self, $transaction, $recipient) = @_;

  # Check if this IP is allowed to relay
  my @relay_clients = $self->qp->config("relayclients");
  my $more_relay_clients = $self->qp->config("morerelayclients", "map");
  my %relay_clients = map { $_ => 1 } @relay_clients;
  my $client_ip = $self->qp->connection->remote_ip;
  while ($client_ip) {
    if (exists($ENV{RELAYCLIENT}) or
        exists($relay_clients{$client_ip}) or
        exists($more_relay_clients->{$client_ip}))
    {
      $ENV{RELAYCLIENT} = '';
      $transaction->relaying(1);
    }
    $client_ip =~ s/\d+\.?$//; # strip off another 8 bits
  }
 
  return(DECLINED);
}

sub check_relay_rcpt {
  my ($self, $transaction, $recipient) = @_;
  my $host = lc $recipient->host;

  # Check if this is an relaying user
  return(OK) if ( $transaction->{_relaying} || exists($ENV{RELAYCLIENT}) );

  # Otherwise check for acceptance of the recipient host
  my @rcpt_hosts = ($self->qp->config("me"), $self->qp->config("rcpthosts"));
  
  # Allow 'no @' addresses for 'postmaster' and 'abuse'
  # qmail-smtpd will do this for all users without a domain, but we'll
  # be a bit more picky.  Maybe that's a bad idea.
  my $user = $recipient->user;
  $host = $self->qp->config("me")
    if ($host eq "" && (lc $user eq "postmaster" || lc $user eq "abuse"));

  # Check if this recipient host is allowed
  for my $allowed (@rcpt_hosts) {
    $allowed =~ s/^\s*(\S+)/$1/;
    return (OK) if $host eq lc $allowed;
    return (OK) if substr($allowed,0,1) eq "." and $host =~ m/\Q$allowed\E$/i;
  }

  my $more_rcpt_hosts = $self->qp->config('morercpthosts', 'map');
  return (OK) if exists $more_rcpt_hosts->{$host};

  return (DENY);
}

Reply via email to