[Postfixbuch-users] Dovecot-Userquota in Postfix nutzen
Gregor Hermens
gregor at a-mazing.de
Di Feb 22 16:56:29 CET 2011
Am Dienstag, 22. Februar 2011 schrieb Jan Phillip Greimann:
> Am 22.02.2011 16:00, schrieb Gregor Hermens:
> > Ich habe mir dafür einen kleinen Policy-Daemon geschrieben.
>
> Kann man diesen vielleicht zu Anschauungszwecken zeigen?
Der Code stammt zum größten Teil aus dem Beispiel-Daemon, der mit den Postfix
sourcen geliefert wird: ~/examples/smtpd.policy/greylist.pl
und dem Policy-Readme: http://www.postfix.org/SMTPD_POLICY_README.html
Die SQL-Abfrage in Zeile 92 habe ich gekürzt, da sie spezifisch für meine
Tabellenstruktur ist.
Gestartet wird der Daemon per Spawn aus der master.cf, eingebunden ist er in
recipient- und end-of-data-restrictions. Beim ersten Aufrauf verlässt er sich
auf die vom Client übermittelte Größe und kann noch einzelne Empfänger
ablehnen, bei zweiten Aufruf ist die tatsächliche Größe bekannt, dafür müssen
Mails mit mehr als einem Empfänger jetzt trotzdem angenommen werden. Ein paar
wenige Bounces bleiben also erhalten.
Der Code:
policyd-quota.pl:
----------------------------------------------------------------------------
!#/usr/bin/perl
use DBI;
use Fcntl;
use Sys::Syslog qw(:DEFAULT setlogsock);
#
# Usage: policyd-quota.pl [-v]
#
# Delegated Postfix SMTPD policy server. This server implements
# quota checking against a mySQL based dovecot quota dict. Logging is
# sent to syslogd.
#
$db_type = 'mysql';
$db_host = 'localhost';
$db_user = 'dbuser';
$db_pass = 'dbpass';
$db_name = 'dbname';
#
# Syslogging options for verbose mode and for fatal errors.
# NOTE: comment out the $syslog_socktype line if syslogging does not
# work on your system.
#
$syslog_socktype = 'unix'; # inet, unix, stream, console
$syslog_facility="mail";
$syslog_options="pid";
$syslog_priority="info";
#
# SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# table. Request attributes are available via the %attr hash.
#
sub smtpd_access_policy {
my($key, $free);
if("END-OF-MESSAGE" == $attr{"protocol_state"} && 1 <
$attr{"recipient_count"}) {
syslog $syslog_priority, "more than one recipient in END-OF-
MESSAGE state" if $verbose;
return "dunno";
}
if(0 == $attr{"size"}) {
syslog $syslog_priority, "cannot establish size of mail for
recipient: %s", $attr{"recipient"} if $verbose;
return "dunno";
}
open_database() unless $dbh;
$key = lc $attr{"recipient"};
$free = read_database($key);
if(defined $free) {
syslog $syslog_priority, "recipient: %s, free: %d bytes, size:
%d bytes", $attr{"recipient"}, $free, $attr{"size"} if $verbose;
if($attr{"size"} <= $free) {
return "dunno";
} else {
return "550 5.2.2 Mailbox full"
}
} else {
syslog $syslog_priority, "cannot establish free space for
recipient: %s", $attr{"recipient"} if $verbose;
return "dunno";
}
}
#
# Log an error and abort.
#
sub fatal_exit {
my($first) = shift(@_);
syslog "err", "fatal: $first", @_;
exit 1;
}
#
# Open database.
#
sub open_database {
$dbh = DBI->connect("DBI:$db_type:$db_name:$db_host", "$db_user",
"$db_pass", { PrintError => 0, AutoCommit => 1,}) || fatal_exit "Error
connecting to database: %s", $DBI::errstr;
}
#
# Read database.
#
sub read_database {
my($key) = @_;
my($value);
my($query);
$key = $dbh->quote($key);
$query = "SELECT `quota`, `storage` FROM [...] WHERE `address` = $key
[...] LIMIT 1";
my $sth = $dbh->prepare($query) || fatal_exit "DB error: %s", $dbh-
>errstr();
$sth->execute() || fatal_exit "DB error: %s", $dbh->errstr();
my $row = $sth->fetchrow_hashref() || return undef;
syslog $syslog_priority, "Database results: quota: %dk, storage: %d",
$row->{quota}, $row->{storage} if $verbose;
$value = $row->{quota} * 1024 - $row->{storage};
return $value;
}
#
# This process runs as a daemon, so it can't log to a terminal. Use
# syslog so that people can actually see our messages.
#
setlogsock $syslog_socktype;
openlog 'policyd-quota', $syslog_options, $syslog_facility;
#
# We don't need getopt() for now.
#
while ($option = shift(@ARGV)) {
if ($option eq "-v") {
$verbose = 1;
} else {
syslog $syslog_priority, "Invalid option: %s. Usage: %s [-v]",
$option, $0;
exit 1;
}
}
#
# Unbuffer standard output.
#
select((select(STDOUT), $| = 1)[0]);
#
# Receive a bunch of attributes, evaluate the policy, send the result.
#
while (<STDIN>) {
if (/([^=]+)=(.*)\n/) {
$attr{substr($1, 0, 512)} = substr($2, 0, 512);
} elsif ($_ eq "\n") {
if ($verbose) {
for (keys %attr) {
syslog $syslog_priority, "Attribute: %s=%s",
$_, $attr{$_};
}
}
fatal_exit "unrecognized request type: '%s'", $attr{"request"}
unless $attr{"request"} eq "smtpd_access_policy";
$action = smtpd_access_policy();
syslog $syslog_priority, "Action: %s; Recipient: <%s>, Size:
%s", $action, lc $attr{"recipient"}, $attr{"size"};
print STDOUT "action=$action\n\n";
%attr = ();
} else {
chop;
syslog $syslog_priority, "warning: ignoring garbage: %.100s",
$_;
}
}
-------------------------------------------------------------------------------
Gruß,
Gregor
--
@mazing fon +49 8142 6528665
Gregor Hermens fax +49 8142 6528669
Brucker Strasse 12 gregor.hermens at a-mazing.de
D-82216 Gernlinden http://www.a-mazing.de/
Mehr Informationen über die Mailingliste Postfixbuch-users