ADD: initial version of rcpt_mysql plugin
This commit is contained in:
parent
d3cf60d2c8
commit
c4f5490abd
232
plugins/rcpt_mysql
Normal file
232
plugins/rcpt_mysql
Normal file
@ -0,0 +1,232 @@
|
||||
use Qpsmtpd::Constants;
|
||||
use DBI;
|
||||
|
||||
|
||||
#
|
||||
# called when initializing the plugin
|
||||
#
|
||||
sub init {
|
||||
my ($self, $qp, %args) = @_;
|
||||
|
||||
# some default values
|
||||
$self->{database} = "mail";
|
||||
$self->{host} = "localhost";
|
||||
$self->{port} = "3301";
|
||||
$self->{user} = undef;
|
||||
$self->{pass} = undef;
|
||||
$self->{rawquery}= undef;
|
||||
|
||||
# the cache timeout in seconds
|
||||
$self->{cacheTimeout} = 500; #seconds
|
||||
|
||||
# a map for caching database repsonses
|
||||
# done on a per email basis
|
||||
$self->{cache} = {};
|
||||
|
||||
# parse the configuration file
|
||||
$self->parseConfig();
|
||||
|
||||
$self->createQuery();
|
||||
|
||||
$self->createDSN();
|
||||
}
|
||||
|
||||
sub createDSN
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
my $dsn = "DBI:MariaDB:database=" . $self->{database} . ";host=" . $self->{host} . ";port=" . $self->{port};
|
||||
$self->{dsn} = $dsn;
|
||||
|
||||
}
|
||||
|
||||
sub createQuery
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
#
|
||||
# !u the user part of the rcpt
|
||||
# !d the domain part of the rcpt
|
||||
|
||||
my @params;
|
||||
my @variables = split /!/,$self->{rawquery};
|
||||
|
||||
for my $v (@variables)
|
||||
{
|
||||
if ($v eq "u")
|
||||
{
|
||||
push(@params,"user");
|
||||
}
|
||||
elsif ($v eq "d")
|
||||
{
|
||||
push(@params,"domain")
|
||||
}
|
||||
}
|
||||
|
||||
$self->{sqlparams}=\@params;
|
||||
|
||||
my $query = $self->{rawquery};
|
||||
$query =~s/!u/?/g;
|
||||
$query =~s/!d/?/g;
|
||||
|
||||
$self->{sqlquery}=$query;
|
||||
|
||||
}
|
||||
|
||||
sub prepareParams
|
||||
{
|
||||
my $self = shift;
|
||||
my $recipient = shift;
|
||||
|
||||
my @params;
|
||||
|
||||
for my $p (@params)
|
||||
{
|
||||
if ($p eq "user")
|
||||
{
|
||||
push(@params,$recipient->user);
|
||||
}
|
||||
elsif($p eq "domain")
|
||||
{
|
||||
push(@params,$recipient->user);
|
||||
}
|
||||
}
|
||||
|
||||
return @params;
|
||||
}
|
||||
|
||||
sub parseConfig
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# parse the configuration file of this plugin line by line
|
||||
my @config = $self->qp->config('rcpt_mysql');
|
||||
|
||||
for my $line (@config)
|
||||
{
|
||||
my @value = split /:=/, $line;
|
||||
|
||||
my $key = lc($value[0]);
|
||||
|
||||
if ( $key eq "database")
|
||||
{
|
||||
$self->{database} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "host")
|
||||
{
|
||||
$self->{host} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "user")
|
||||
{
|
||||
$self->{user} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "pass")
|
||||
{
|
||||
$self->{pass} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "port")
|
||||
{
|
||||
$self->{port} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "cachetimeout")
|
||||
{
|
||||
$self->{cacheTimeout} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "pass")
|
||||
{
|
||||
$self->{pass} = $value[1];
|
||||
}
|
||||
elsif ( $key eq "query")
|
||||
{
|
||||
$self->{rawquery} = $value[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
warn("Key \"" . $key . "\" is an unknown configuration option");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub askCache
|
||||
{
|
||||
my $self = shift;
|
||||
my $recipient = shift;
|
||||
|
||||
# combine to a normal recipient
|
||||
my $rcpt = lc $recipient->user . '@' . lc $recipient->host;
|
||||
|
||||
# check if there is something in the cache for this recipient
|
||||
if ($self->{cache}->{$rcpt} && $self->{cache}->{$rcpt}->{time}-time() <= $self->{cacheTimeout}) {
|
||||
if ($self->{cache}->{$rcpt}->{hit} == 0 )
|
||||
{
|
||||
return DECLINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub askDatabase
|
||||
{
|
||||
my $self = shift;
|
||||
my $recipient = shift;
|
||||
my $dbh = DBI::connect($self->{dsn}, $self->{user}, $self->{pass},{ RaiseError => 0, PrintError => 0 });
|
||||
|
||||
if ($dbh->err())
|
||||
{
|
||||
warn("error connecting to DB: " . $dbh->errstr());
|
||||
return DENYSOFT;
|
||||
}
|
||||
|
||||
my $sth = $dbh->prepare($self->{sqlquery});
|
||||
if ($sth->err())
|
||||
{
|
||||
warn("error preparing query: " . $sth->errstr());
|
||||
return DENYSOFT;
|
||||
}
|
||||
|
||||
$sth->execute($self->prepareParams($recipient));
|
||||
|
||||
my $ret = DECLINED;
|
||||
|
||||
if ($sth->rows > 0)
|
||||
{
|
||||
$ret = OK;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
#
|
||||
# plugin hook called if rcpt_to is issued within the smtp session
|
||||
#
|
||||
sub rcpt_to {
|
||||
my ($self, $transaction, $recipient) = @_;
|
||||
|
||||
# some basic validations
|
||||
return DECLINED unless $recipient->host && $recipient->user;
|
||||
|
||||
# ask the cache for results
|
||||
my $cacheResult = $self->askCache($recipient);
|
||||
return $cacheResult if defined($cacheResult);
|
||||
|
||||
# ask the database for results
|
||||
return $self->askDatabase($recipient);
|
||||
}
|
||||
|
||||
#
|
||||
# called for registering all the hooks
|
||||
#
|
||||
sub register {
|
||||
my ($self, $qp, %args) = @_;
|
||||
|
||||
|
||||
$self->register_hook("rcpt", "rcpt_handler");
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user