use strict;
use warnings;
+use URI;
use Data::Dumper;
use PVE::Tools;
sub properties {
return {
+ advfilter => {
+ description => "Use advanced filters for statistic.",
+ type => 'boolean',
+ default => 1,
+ },
dailyreport => {
description => "Send daily reports.",
type => 'boolean',
default => 1,
},
+ statlifetime => {
+ description => "User Statistics Lifetime (days)",
+ type => 'integer',
+ default => 7,
+ minimum => 1,
+ },
demo => {
description => "Demo mode - do not start SMTP filter.",
type => 'boolean',
type => 'string', format => 'email',
default => 'admin@domain.tld',
},
- proxyport => {
- description => "HTTP proxy port.",
- type => 'integer',
- minimum => 1,
- default => 8080,
- },
- proxyserver => {
- description => "HTTP proxy server address.",
- type => 'string',
- },
- proxyuser => {
- description => "HTTP proxy user name.",
- type => 'string',
- },
- proxypassword => {
- description => "HTTP proxy password.",
+ http_proxy => {
+ description => "Specify external http proxy which is used for downloads (example: 'http://username:password\@host:port/')",
type => 'string',
+ pattern => "http://.*",
},
};
}
sub options {
return {
+ advfilter => { optional => 1 },
+ statlifetime => { optional => 1 },
dailyreport => { optional => 1 },
demo => { optional => 1 },
email => { optional => 1 },
- proxyport => { optional => 1 },
- proxyserver => { optional => 1 },
- proxyuser => { optional => 1 },
- proxypassword => { optional => 1 },
+ http_proxy => { optional => 1 },
};
}
type => 'boolean',
default => 1,
},
- use_ocr => {
- description => "Enable OCR to scan pictures.",
- type => 'boolean',
- default => 0,
- },
wl_bounce_relays => {
description => "Whitelist legitimate bounce relays.",
type => 'string',
},
+ clamav_heuristic_score => {
+ description => "Score for ClamaAV heuristics (Google Safe Browsing database, PhishingScanURLs, ...).",
+ type => 'integer',
+ minimum => 0,
+ maximum => 1000,
+ default => 3,
+ },
bounce_score => {
description => "Additional score for bounce mails.",
type => 'integer',
description => "Maximum size of spam messages in bytes.",
type => 'integer',
minimum => 64,
- default => 200*1024,
+ default => 256*1024,
},
};
}
return {
use_awl => { optional => 1 },
use_razor => { optional => 1 },
- use_ocr => { optional => 1 },
wl_bounce_relays => { optional => 1 },
languages => { optional => 1 },
use_bayes => { optional => 1 },
+ clamav_heuristic_score => { optional => 1 },
bounce_score => { optional => 1 },
rbl_checks => { optional => 1 },
maxspamsize => { optional => 1 },
};
}
+package PMG::Config::SpamQuarantine;
+
+use strict;
+use warnings;
+
+use base qw(PMG::Config::Base);
+
+sub type {
+ return 'spamquar';
+}
+
+sub properties {
+ return {
+ lifetime => {
+ description => "Quarantine life time (days)",
+ type => 'integer',
+ minimum => 1,
+ default => 7,
+ },
+ authmode => {
+ description => "Authentication mode to access the quarantine interface. Mode 'ticket' allows login using tickets sent with the daily spam report. Mode 'ldap' requires to login using an LDAP account. Finally, mode 'ldapticket' allows both ways.",
+ type => 'string',
+ enum => [qw(ticket ldap ldapticket)],
+ default => 'ticket',
+ },
+ reportstyle => {
+ description => "Spam report style.",
+ type => 'string',
+ enum => [qw(none short verbose custom)],
+ default => 'verbose',
+ },
+ viewimages => {
+ description => "Allow to view images.",
+ type => 'boolean',
+ default => 1,
+ },
+ allowhrefs => {
+ description => "Allow to view hyperlinks.",
+ type => 'boolean',
+ default => 1,
+ },
+ hostname => {
+ description => "Quarantine Host. Usefule if you run a Cluster and want users to connect to a specific host.",
+ type => 'string', format => 'address',
+ },
+ mailfrom => {
+ description => "Text for 'From' header in daily spam report mails.",
+ type => 'string',
+ },
+ };
+}
+
+sub options {
+ return {
+ mailfrom => { optional => 1 },
+ hostname => { optional => 1 },
+ lifetime => { optional => 1 },
+ authmode => { optional => 1 },
+ reportstyle => { optional => 1 },
+ viewimages => { optional => 1 },
+ allowhrefs => { optional => 1 },
+ };
+}
+
+package PMG::Config::VirusQuarantine;
+
+use strict;
+use warnings;
+
+use base qw(PMG::Config::Base);
+
+sub type {
+ return 'virusquar';
+}
+
+sub properties {
+ return {};
+}
+
+sub options {
+ return {
+ lifetime => { optional => 1 },
+ viewimages => { optional => 1 },
+ allowhrefs => { optional => 1 },
+ };
+}
+
package PMG::Config::ClamAV;
use strict;
minimum => 0,
default => 0,
},
+ safebrowsing => {
+ description => "Enables support for Google Safe Browsing.",
+ type => 'boolean',
+ default => 1
+ },
};
}
maxscansize => { optional => 1 },
dbmirror => { optional => 1 },
maxcccount => { optional => 1 },
+ safebrowsing => { optional => 1 },
};
}
type => 'integer',
minimum => 1,
maximum => 65535,
- default => 25,
+ default => 26,
},
ext_port => {
description => "SMTP port number for incoming mail (untrusted). This must be a different number than 'int_port'.",
type => 'integer',
minimum => 1,
maximum => 65535,
- default => 26,
+ default => 25,
},
relay => {
description => "The default mail delivery transport (incoming mails).",
minimum => 0,
default => 4,
},
- use_rbl => {
- description => "Use Realtime Blacklists.",
+ tls => {
+ description => "Enable TLS.",
type => 'boolean',
- default => 1,
+ default => 0,
},
- tls => {
- description => "Use TLS.",
+ tlslog => {
+ description => "Enable TLS Logging.",
+ type => 'boolean',
+ default => 0,
+ },
+ tlsheader => {
+ description => "Add TLS received header.",
type => 'boolean',
default => 0,
},
},
dnsbl_sites => {
description => "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).",
- type => 'string',
+ type => 'string', format => 'dnsbl-entry-list',
},
};
}
max_smtpd_out => { optional => 1 },
greylist => { optional => 1 },
helotests => { optional => 1 },
- use_rbl => { optional => 1 },
tls => { optional => 1 },
+ tlslog => { optional => 1 },
+ tlsheader => { optional => 1 },
spf => { optional => 1 },
maxsize => { optional => 1 },
banner => { optional => 1 },
dnsbl_sites => { optional => 1 },
};
}
+
package PMG::Config;
use strict;
use Template;
use PVE::SafeSyslog;
-use PVE::Tools;
+use PVE::Tools qw($IPV4RE $IPV6RE);
use PVE::INotify;
+use PVE::JSONSchema;
+
+use PMG::Cluster;
PMG::Config::Admin->register();
PMG::Config::Mail->register();
+PMG::Config::SpamQuarantine->register();
+PMG::Config::VirusQuarantine->register();
PMG::Config::Spam->register();
PMG::Config::ClamAV->register();
# initialize all plugins
PMG::Config::Base->init();
+PVE::JSONSchema::register_format(
+ 'transport-domain', \&pmg_verify_transport_domain);
+
+sub pmg_verify_transport_domain {
+ my ($name, $noerr) = @_;
+
+ # like dns-name, but can contain leading dot
+ my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)";
+
+ if ($name !~ /^\.?(${namere}\.)*${namere}$/) {
+ return undef if $noerr;
+ die "value does not look like a valid transport domain\n";
+ }
+ return $name;
+}
+
+PVE::JSONSchema::register_format(
+ 'dnsbl-entry', \&pmg_verify_dnsbl_entry);
+
+sub pmg_verify_dnsbl_entry {
+ my ($name, $noerr) = @_;
+
+ # like dns-name, but can contain trailing weight: 'domain*<WEIGHT>'
+ my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)";
+
+ if ($name !~ /^(${namere}\.)*${namere}(\*\-?\d+)?$/) {
+ return undef if $noerr;
+ die "value '$name' does not look like a valid dnsbl entry\n";
+ }
+ return $name;
+}
sub new {
my ($type) = @_;
# get section value or default
sub get {
- my ($self, $section, $key) = @_;
+ my ($self, $section, $key, $nodefault) = @_;
my $pdata = PMG::Config::Base->private();
my $pdesc = $pdata->{propertyList}->{$key};
return $value;
}
+ return undef if $nodefault;
+
return $pdesc->{default};
}
sub read_pmg_domains {
my ($filename, $fh) = @_;
- my $domains = [];
+ my $domains = {};
+ my $comment = '';
if (defined($fh)) {
while (defined(my $line = <$fh>)) {
- if ($line =~ m/^\s*(\S+)\s*$/) {
+ chomp $line;
+ next if $line =~ m/^\s*$/;
+ if ($line =~ m/^#(.*)\s*$/) {
+ $comment = $1;
+ next;
+ }
+ if ($line =~ m/^(\S+)\s.*$/) {
my $domain = $1;
- push @$domains, $domain;
+ $domains->{$domain} = {
+ domain => $domain, comment => $comment };
+ $comment = '';
+ } else {
+ warn "parse error in '$filename': $line\n";
+ $comment = '';
}
}
}
}
sub write_pmg_domains {
- my ($filename, $fh, $domain) = @_;
+ my ($filename, $fh, $domains) = @_;
- foreach my $domain (sort @$domain) {
- PVE::Tools::safe_print($filename, $fh, "$domain\n");
+ foreach my $domain (sort keys %$domains) {
+ my $comment = $domains->{$domain}->{comment};
+ PVE::Tools::safe_print($filename, $fh, "#$comment\n")
+ if defined($comment) && $comment !~ m/^\s*$/;
+
+ PVE::Tools::safe_print($filename, $fh, "$domain 1\n");
}
}
\&write_pmg_domains,
undef, always_call_parser => 1);
-my $transport_map_filename = "/etc/postfix/transport";
+my $mynetworks_filename = "/etc/pmg/mynetworks";
+
+sub read_pmg_mynetworks {
+ my ($filename, $fh) = @_;
+
+ my $mynetworks = {};
+
+ my $comment = '';
+ if (defined($fh)) {
+ while (defined(my $line = <$fh>)) {
+ chomp $line;
+ next if $line =~ m/^\s*$/;
+ if ($line =~ m!^((?:$IPV4RE|$IPV6RE))/(\d+)\s*(?:#(.*)\s*)?$!) {
+ my ($network, $prefix_size, $comment) = ($1, $2, $3);
+ my $cidr = "$network/${prefix_size}";
+ $mynetworks->{$cidr} = {
+ cidr => $cidr,
+ network_address => $network,
+ prefix_size => $prefix_size,
+ comment => $comment // '',
+ };
+ } else {
+ warn "parse error in '$filename': $line\n";
+ }
+ }
+ }
+
+ return $mynetworks;
+}
+
+sub write_pmg_mynetworks {
+ my ($filename, $fh, $mynetworks) = @_;
+
+ foreach my $cidr (sort keys %$mynetworks) {
+ my $data = $mynetworks->{$cidr};
+ my $comment = $data->{comment} // '*';
+ PVE::Tools::safe_print($filename, $fh, "$cidr #$comment\n");
+ }
+}
+
+PVE::INotify::register_file('mynetworks', $mynetworks_filename,
+ \&read_pmg_mynetworks,
+ \&write_pmg_mynetworks,
+ undef, always_call_parser => 1);
+
+my $tls_policy_map_filename = "/etc/pmg/tls_policy";
+
+sub postmap_tls_policy {
+ PMG::Utils::run_postmap($tls_policy_map_filename);
+}
+
+my $transport_map_filename = "/etc/pmg/transport";
+
+sub postmap_pmg_transport {
+ PMG::Utils::run_postmap($transport_map_filename);
+}
sub read_transport_map {
my ($filename, $fh) = @_;
my $res = {};
+ my $comment = '';
+
while (defined(my $line = <$fh>)) {
chomp $line;
next if $line =~ m/^\s*$/;
- next if $line =~ m/^\s*\#/;
+ if ($line =~ m/^#(.*)\s*$/) {
+ $comment = $1;
+ next;
+ }
- if ($line =~ m/^(\S+)\s+smtp:([^\s:]+):(\d+)\s*$/) {
- my $domain = $1;
- my $host = $2;
- my $port =$3;
- my $nomx;
+ my $parse_error = sub {
+ my ($err) = @_;
+ warn "parse error in '$filename': $line - $err";
+ $comment = '';
+ };
+
+ if ($line =~ m/^(\S+)\s+smtp:(\S+):(\d+)\s*$/) {
+ my ($domain, $host, $port) = ($1, $2, $3);
+ eval { pmg_verify_transport_domain($domain); };
+ if (my $err = $@) {
+ $parse_error->($err);
+ next;
+ }
+ my $use_mx = 1;
if ($host =~ m/^\[(.*)\]$/) {
$host = $1;
- $nomx = 1;
+ $use_mx = 0;
}
- my $key = "$host:$port";
-
- $res->{$key}->{nomx} = $nomx;
- $res->{$key}->{host} = $host;
- $res->{$key}->{port} = $port;
- $res->{$key}->{transport} = $key;
+ eval { PVE::JSONSchema::pve_verify_address($host); };
+ if (my $err = $@) {
+ $parse_error->($err);
+ next;
+ }
- push @{$res->{$key}->{domains}}, $domain;
+ my $data = {
+ domain => $domain,
+ host => $host,
+ port => $port,
+ use_mx => $use_mx,
+ comment => $comment,
+ };
+ $res->{$domain} = $data;
+ $comment = '';
+ } else {
+ $parse_error->('wrong format');
}
}
- my $ta = [];
-
- foreach my $t (sort keys %$res) {
- push @$ta, $res->{$t};
- }
-
- return $ta;
+ return $res;
}
-sub write_ransport_map {
+sub write_transport_map {
my ($filename, $fh, $tmap) = @_;
return if !$tmap;
- foreach my $t (sort { $a->{transport} cmp $b->{transport} } @$tmap) {
- my $domains = $t->{domains};
+ foreach my $domain (sort keys %$tmap) {
+ my $data = $tmap->{$domain};
- foreach my $d (sort @$domains) {
- if ($t->{nomx}) {
- PVE::Tools::safe_print($filename, $fh, "$d smtp:[$t->{host}]:$t->{port}\n");
- } else {
- PVE::Tools::safe_print($filename, $fh, "$d smtp:$t->{host}:$t->{port}\n");
- }
+ my $comment = $data->{comment};
+ PVE::Tools::safe_print($filename, $fh, "#$comment\n")
+ if defined($comment) && $comment !~ m/^\s*$/;
+
+ my $use_mx = $data->{use_mx};
+ $use_mx = 0 if $data->{host} =~ m/^(?:$IPV4RE|$IPV6RE)$/;
+
+ if ($use_mx) {
+ PVE::Tools::safe_print(
+ $filename, $fh, "$data->{domain} smtp:$data->{host}:$data->{port}\n");
+ } else {
+ PVE::Tools::safe_print(
+ $filename, $fh, "$data->{domain} smtp:[$data->{host}]:$data->{port}\n");
}
}
}
PVE::INotify::register_file('transport', $transport_map_filename,
\&read_transport_map,
- \&write_ransport_map,
+ \&write_transport_map,
undef, always_call_parser => 1);
# config file generation using templates
$vars->{ipconfig}->{int_ip} = $int_ip;
# $vars->{ipconfig}->{int_net_cidr} = $int_net_cidr;
- my $transportnets = []; # fixme
+ my $transportnets = [];
+
+ if (my $tmap = PVE::INotify::read_file('transport')) {
+ foreach my $domain (sort keys %$tmap) {
+ my $data = $tmap->{$domain};
+ my $host = $data->{host};
+ if ($host =~ m/^$IPV4RE$/) {
+ push @$transportnets, "$host/32";
+ } elsif ($host =~ m/^$IPV6RE$/) {
+ push @$transportnets, "[$host]/128";
+ }
+ }
+ }
+
$vars->{postfix}->{transportnets} = join(' ', @$transportnets);
my $mynetworks = [ '127.0.0.0/8', '[::1]/128' ];
- push @$mynetworks, @$transportnets;
push @$mynetworks, $int_net_cidr;
+ my $netlist = PVE::INotify::read_file('mynetworks');
+ push @$mynetworks, keys %$netlist;
+
+ push @$mynetworks, @$transportnets;
+
# add default relay to mynetworks
if (my $relay = $self->get('mail', 'relay')) {
- if (Net::IP::ip_is_ipv4($relay)) {
+ if ($relay =~ m/^$IPV4RE$/) {
push @$mynetworks, "$relay/32";
- } elsif (Net::IP::ip_is_ipv6($relay)) {
+ } elsif ($relay =~ m/^$IPV6RE$/) {
push @$mynetworks, "[$relay]/128";
} else {
# DNS name - do nothing ?
$vars->{postfix}->{mynetworks} = join(' ', @$mynetworks);
+ # normalize dnsbl_sites
+ my @dnsbl_sites = PVE::Tools::split_list($vars->{pmg}->{mail}->{dnsbl_sites});
+ if (scalar(@dnsbl_sites)) {
+ $vars->{postfix}->{dnsbl_sites} = join(',', @dnsbl_sites);
+ }
+
my $usepolicy = 0;
$usepolicy = 1 if $self->get('mail', 'greylist') ||
- $self->get('mail', 'spf') || $self->get('mail', 'use_rbl');
+ $self->get('mail', 'spf');
$vars->{postfix}->{usepolicy} = $usepolicy;
my $resolv = PVE::INotify::read_file('resolvconf');
$vars->{dns}->{hostname} = $nodename;
- $vars->{dns}->{domain} = $resolv->{search};
+
+ my $domain = $resolv->{search} // 'localdomain';
+ $vars->{dns}->{domain} = $domain;
+
+ my $wlbr = "$nodename.$domain";
+ foreach my $r (PVE::Tools::split_list($vars->{pmg}->{spam}->{wl_bounce_relays})) {
+ $wlbr .= " $r"
+ }
+ $vars->{composed}->{wl_bounce_relays} = $wlbr;
+
+ if (my $proxy = $vars->{pmg}->{admin}->{http_proxy}) {
+ eval {
+ my $uri = URI->new($proxy);
+ my $host = $uri->host;
+ my $port = $uri->port // 8080;
+ if ($host) {
+ my $data = { host => $host, port => $port };
+ if (my $ui = $uri->userinfo) {
+ my ($username, $pw) = split(/:/, $ui, 2);
+ $data->{username} = $username;
+ $data->{password} = $pw if defined($pw);
+ }
+ $vars->{proxy} = $data;
+ }
+ };
+ warn "parse http_proxy failed - $@" if $@;
+ }
return $vars;
}
+# use one global TT cache
+our $tt_include_path = ['/etc/pmg/templates' ,'/var/lib/pmg/templates' ];
+
+my $template_toolkit;
+
+sub get_template_toolkit {
+
+ return $template_toolkit if $template_toolkit;
+
+ $template_toolkit = Template->new({ INCLUDE_PATH => $tt_include_path });
+
+ return $template_toolkit;
+}
+
# rewrite file from template
# return true if file has changed
sub rewrite_config_file {
my $demo = $self->get('admin', 'demo');
- my $srcfn = ($tmplname =~ m|^.?/|) ?
- $tmplname : "/var/lib/pmg/templates/$tmplname";
-
if ($demo) {
- my $demosrc = "$srcfn.demo";
- $srcfn = $demosrc if -f $demosrc;
+ my $demosrc = "$tmplname.demo";
+ $tmplname = $demosrc if -f "/var/lib/pmg/templates/$demosrc";
}
my ($perm, $uid, $gid);
- my $srcfd = IO::File->new ($srcfn, "r")
- || die "cant read template '$srcfn' - $!: ERROR";
-
- if ($dstfn eq '/etc/fetchmailrc') {
- (undef, undef, $uid, $gid) = getpwnam('fetchmail');
- $perm = 0600;
- } elsif ($dstfn eq '/etc/clamav/freshclam.conf') {
+ if ($dstfn eq '/etc/clamav/freshclam.conf') {
# needed if file contains a HTTPProxyPasswort
$uid = getpwnam('clamav');
$perm = 0600;
}
- my $template = Template->new({});
+ my $tt = get_template_toolkit();
my $vars = $self->get_template_vars();
my $output = '';
- $template->process($srcfd, $vars, \$output) ||
- die $template->error();
-
- $srcfd->close();
+ $tt->process($tmplname, $vars, \$output) ||
+ die $tt->error() . "\n";
my $old = PVE::Tools::file_get_contents($dstfn, 128*1024) if -f $dstfn;
PVE::Tools::run_command(['razor-admin', '-register'], timeout => $timeout);
};
my $err = $@;
- syslog('info', msgquote ("registering razor failed: $err")) if $err;
+ syslog('info', "registering razor failed: $err") if $err;
}
}
return 1;
}
+my $write_smtp_whitelist = sub {
+ my ($filename, $data, $action) = @_;
+
+ $action = 'OK' if !$action;
+
+ my $old = PVE::Tools::file_get_contents($filename, 1024*1024)
+ if -f $filename;
+
+ my $new = '';
+ foreach my $k (sort keys %$data) {
+ $new .= "$k $action\n";
+ }
+
+ return 0 if defined($old) && ($old eq $new); # no change
+
+ PVE::Tools::file_set_contents($filename, $new);
+
+ PMG::Utils::run_postmap($filename);
+
+ return 1;
+};
+
+sub rewrite_postfix_whitelist {
+ my ($rulecache) = @_;
+
+ # see man page for regexp_table for postfix regex table format
+
+ # we use a hash to avoid duplicate entries in regex tables
+ my $tolist = {};
+ my $fromlist = {};
+ my $clientlist = {};
+
+ foreach my $obj (@{$rulecache->{"greylist:receiver"}}) {
+ my $oclass = ref($obj);
+ if ($oclass eq 'PMG::RuleDB::Receiver') {
+ my $addr = PMG::Utils::quote_regex($obj->{address});
+ $tolist->{"/^$addr\$/"} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::ReceiverDomain') {
+ my $addr = PMG::Utils::quote_regex($obj->{address});
+ $tolist->{"/^.+\@$addr\$/"} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::ReceiverRegex') {
+ my $addr = $obj->{address};
+ $addr =~ s|/|\\/|g;
+ $tolist->{"/^$addr\$/"} = 1;
+ }
+ }
+
+ foreach my $obj (@{$rulecache->{"greylist:sender"}}) {
+ my $oclass = ref($obj);
+ my $addr = PMG::Utils::quote_regex($obj->{address});
+ if ($oclass eq 'PMG::RuleDB::EMail') {
+ my $addr = PMG::Utils::quote_regex($obj->{address});
+ $fromlist->{"/^$addr\$/"} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::Domain') {
+ my $addr = PMG::Utils::quote_regex($obj->{address});
+ $fromlist->{"/^.+\@$addr\$/"} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::WhoRegex') {
+ my $addr = $obj->{address};
+ $addr =~ s|/|\\/|g;
+ $fromlist->{"/^$addr\$/"} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::IPAddress') {
+ $clientlist->{$obj->{address}} = 1;
+ } elsif ($oclass eq 'PMG::RuleDB::IPNet') {
+ $clientlist->{$obj->{address}} = 1;
+ }
+ }
+
+ $write_smtp_whitelist->("/etc/postfix/senderaccess", $fromlist);
+ $write_smtp_whitelist->("/etc/postfix/rcptaccess", $tolist);
+ $write_smtp_whitelist->("/etc/postfix/clientaccess", $clientlist);
+ $write_smtp_whitelist->("/etc/postfix/postscreen_access", $clientlist, 'permit');
+};
+
# rewrite /etc/postfix/*
sub rewrite_config_postfix {
- my ($self) = @_;
+ my ($self, $rulecache) = @_;
# make sure we have required files (else postfix start fails)
- IO::File->new($domainsfilename, 'a', 0644);
IO::File->new($transport_map_filename, 'a', 0644);
my $changes = 0;
eval {
PMG::Utils::gen_proxmox_tls_cert();
};
- syslog ('info', msgquote ("generating certificate failed: $@")) if $@;
+ syslog ('info', "generating certificate failed: $@") if $@;
}
$changes = 1 if $self->rewrite_config_file(
$changes = 1 if $self->rewrite_config_file(
'master.cf.in', '/etc/postfix/master.cf');
- #rewrite_config_transports ($class);
- #rewrite_config_whitelist ($class);
- #rewrite_config_tls_policy ($class);
+ # make sure we have required files (else postfix start fails)
+ # Note: postmap need a valid /etc/postfix/main.cf configuration
+ postmap_pmg_domains();
+ postmap_pmg_transport();
+ postmap_tls_policy();
+
+ rewrite_postfix_whitelist($rulecache) if $rulecache;
# make sure aliases.db is up to date
system('/usr/bin/newaliases');
}
sub rewrite_config {
- my ($self, $restart_services) = @_;
+ my ($self, $rulecache, $restart_services, $force_restart) = @_;
- postmap_pmg_domains();
+ $force_restart = {} if ! $force_restart;
- if ($self->rewrite_config_postfix() && $restart_services) {
+ if (($self->rewrite_config_postfix($rulecache) && $restart_services) ||
+ $force_restart->{postfix}) {
PMG::Utils::service_cmd('postfix', 'restart');
}
# does not happen anyways, because config does not change.
}
- if ($self->rewrite_config_spam() && $restart_services) {
+ if (($self->rewrite_config_spam() && $restart_services) ||
+ $force_restart->{spam}) {
PMG::Utils::service_cmd('pmg-smtp-filter', 'restart');
}
- if ($self->rewrite_config_clam() && $restart_services) {
+ if (($self->rewrite_config_clam() && $restart_services) ||
+ $force_restart->{clam}) {
PMG::Utils::service_cmd('clamav-daemon', 'restart');
}
- if ($self->rewrite_config_freshclam() && $restart_services) {
+ if (($self->rewrite_config_freshclam() && $restart_services) ||
+ $force_restart->{freshclam}) {
PMG::Utils::service_cmd('clamav-freshclam', 'restart');
}
-
}
1;