qpsmtpd/plugins/badrcptto

129 lines
3.2 KiB
Plaintext
Raw Normal View History

#!perl -w
POD corrections, additional tests, plugin consistency on files in plugins dir: fixed a number of POD errors formatted some # comments into POD removed bare 1; (these are plugins, not perl modules) most instances of this were copy/pasted from a previous plugin that had it removed instances of # vim ts=N ... they weren't consistent, many didn't match .perltidyrc on modules that failed perl -c tests, added 'use Qpsmtpd::Constants;' Conflicts: plugins/async/check_earlytalker plugins/async/dns_whitelist_soft plugins/async/dnsbl plugins/async/queue/smtp-forward plugins/async/require_resolvable_fromhost plugins/async/rhsbl plugins/async/uribl plugins/auth/auth_checkpassword plugins/auth/auth_cvm_unix_local plugins/auth/auth_flat_file plugins/auth/auth_ldap_bind plugins/auth/auth_vpopmail plugins/auth/auth_vpopmail_sql plugins/auth/authdeny plugins/check_badmailfromto plugins/check_badrcptto_patterns plugins/check_bogus_bounce plugins/check_earlytalker plugins/check_norelay plugins/check_spamhelo plugins/connection_time plugins/dns_whitelist_soft plugins/dnsbl plugins/domainkeys plugins/greylisting plugins/hosts_allow plugins/http_config plugins/logging/adaptive plugins/logging/apache plugins/logging/connection_id plugins/logging/transaction_id plugins/logging/warn plugins/milter plugins/queue/exim-bsmtp plugins/queue/maildir plugins/queue/postfix-queue plugins/queue/smtp-forward plugins/quit_fortune plugins/random_error plugins/rcpt_map plugins/rcpt_regexp plugins/relay_only plugins/require_resolvable_fromhost plugins/rhsbl plugins/sender_permitted_from plugins/spamassassin plugins/tls plugins/tls_cert plugins/uribl plugins/virus/aveclient plugins/virus/bitdefender plugins/virus/clamav plugins/virus/clamdscan plugins/virus/hbedv plugins/virus/kavscanner plugins/virus/klez_filter plugins/virus/sophie plugins/virus/uvscan
2012-04-08 02:11:16 +02:00
=head1 SYNOPSIS
deny connections to recipients in the I<badrcptto> file
like badmailfrom, but for recipient address rather than sender
=head1 CONFIG
Recipients are matched against entries in I<config/badrcptto>. Entries can be
a complete email address, a host entry that starts with an @ symbol, or a
regular expression. For regexp pattern matches, see PATTERNS.
=head1 PATTERNS
This allows special patterns to be denied (e.g. percent hack, bangs,
double ats).
Patterns are stored in the format pattern\sresponse, where pattern
is a Perl pattern expression. Don't forget to anchor the pattern if
you want to restrict it from matching anywhere in the string.
qpsmtpd already ensures that the address contains an @, with something
to the left and right of the @.
=head1 AUTHOR
2002 - original badrcptto plugin - apparently Jim Winstead
https://github.com/smtpd/qpsmtpd/commits/master/plugins/check_badrcptto
2005 - pattern feature, (c) Gordon Rowell <gordonr@gormand.com.au>
2012 - merged the two, refactored, added tests - Matt Simerson
=head1 LICENSE
This software is free software and may be distributed under the same
terms as qpsmtpd itself.
=cut
use strict;
use warnings;
use Qpsmtpd::Constants;
use Qpsmtpd::DSN;
sub hook_rcpt {
my ($self, $transaction, $recipient, %param) = @_;
return DECLINED if $self->is_immune();
my ($host, $to) = $self->get_host_and_to($recipient)
or return DECLINED;
my @badrcptto = $self->qp->config("badrcptto") or do {
$self->log(LOGINFO, "skip, empty config");
return DECLINED;
};
for my $line (@badrcptto) {
$line =~ s/^\s+//g; # trim leading whitespace
my ($bad, $reason) = split /\s+/, $line, 2;
next if !$bad;
if ($self->is_match($to, lc($bad), $host)) {
$self->adjust_karma(-2);
if ($reason) {
return DENY, $reason;
}
return Qpsmtpd::DSN->no_such_user("mail to $bad not accepted here");
}
}
$self->log(LOGINFO, 'pass');
return DECLINED;
}
sub is_match {
my ($self, $to, $bad, $host) = @_;
if ($bad =~ /[\/\^\$\*\+\!\%\?\\]/) { # it's a regexp
$self->log(LOGDEBUG, "badmailfrom pattern ($bad) match for $to");
if ($to =~ /$bad/i) {
$self->log(LOGINFO, 'fail: pattern match');
return 1;
}
return;
}
if ($bad !~ m/\@/) {
$self->log(LOGERROR, "badrcptto: bad config: no \@ sign in $bad");
return;
}
$bad = lc $bad;
$to = lc $to;
if (substr($bad, 0, 1) eq '@') {
if ($bad eq "\@$host") {
$self->log(LOGINFO, 'fail: host match');
return 1;
}
return;
}
if ($bad eq $to) {
$self->log(LOGINFO, 'fail: rcpt match');
return 1;
}
return;
}
sub get_host_and_to {
my ($self, $recipient) = @_;
if (!$recipient) {
$self->log(LOGERROR, 'skip: no recipient!');
return;
}
if (!$recipient->host || !$recipient->user) {
$self->log(LOGINFO, 'skip: missing host or user');
return;
}
my $host = lc $recipient->host;
return $host, lc($recipient->user) . '@' . $host;
}