]> git.proxmox.com Git - pmg-api.git/blobdiff - PMG/Config.pm
fix bug #1646: domains - allow to use wildcard domains
[pmg-api.git] / PMG / Config.pm
index cc80e60fa75422d46e1e79b925d204fadeb3a6b2..18b076aefd0e9c258db86315863a66f56bae4462 100755 (executable)
@@ -144,6 +144,13 @@ sub properties {
            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',
@@ -160,7 +167,7 @@ sub properties {
            description => "Maximum size of spam messages in bytes.",
            type => 'integer',
            minimum => 64,
-           default => 200*1024,
+           default => 256*1024,
        },
     };
 }
@@ -172,6 +179,7 @@ sub options {
        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 },
@@ -220,9 +228,22 @@ sub properties {
            default => 1,
        },
        hostname => {
-           description => "Quarantine Host. Usefule if you run a Cluster and want users to connect to a specific host.",
+           description => "Quarantine Host. Useful if you run a Cluster and want users to connect to a specific host.",
            type => 'string', format => 'address',
        },
+       port => {
+           description => "Quarantine Port. Useful if you have a reverse proxy or port forwarding for the webinterface. Only used for the generated Spam report.",
+           type => 'integer',
+           minimum => 1,
+           maximum => 65535,
+           default => 8006,
+       },
+       protocol => {
+           description => "Quarantine Webinterface Protocol. Useful if you have a reverse proxy for the webinterface. Only used for the generated Spam report.",
+           type => 'string',
+           enum => [qw(http https)],
+           default => 'https',
+       },
        mailfrom => {
            description => "Text for 'From' header in daily spam report mails.",
            type => 'string',
@@ -239,6 +260,8 @@ sub options {
        reportstyle => { optional => 1 },
        viewimages => { optional => 1 },
        allowhrefs => { optional => 1 },
+       port => { optional => 1 },
+       protocol => { optional => 1 },
     };
 }
 
@@ -403,14 +426,14 @@ sub properties {
            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).",
@@ -501,11 +524,6 @@ sub properties {
            minimum => 0,
            default => 4,
        },
-       use_rbl => {
-           description => "Use Realtime Blacklists.",
-           type => 'boolean',
-           default => 1,
-       },
        tls => {
            description => "Enable TLS.",
            type => 'boolean',
@@ -553,7 +571,7 @@ sub properties {
        },
        dnsbl_sites => {
            description => "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).",
-           type => 'string',
+           type => 'string', format => 'dnsbl-entry-list',
        },
     };
 }
@@ -571,7 +589,6 @@ sub options {
        max_smtpd_out => { optional => 1 },
        greylist => { optional => 1 },
        helotests => { optional => 1 },
-       use_rbl => { optional => 1 },
        tls => { optional => 1 },
        tlslog => { optional => 1 },
        tlsheader => { optional => 1 },
@@ -618,6 +635,7 @@ PMG::Config::Base->init();
 
 PVE::JSONSchema::register_format(
     'transport-domain', \&pmg_verify_transport_domain);
+
 sub pmg_verify_transport_domain {
     my ($name, $noerr) = @_;
 
@@ -631,6 +649,22 @@ sub pmg_verify_transport_domain {
     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) = @_;
 
@@ -819,10 +853,6 @@ PVE::INotify::register_file('domains', $domainsfilename,
 
 my $mynetworks_filename = "/etc/pmg/mynetworks";
 
-sub postmap_pmg_mynetworks {
-    PMG::Utils::run_postmap($mynetworks_filename);
-}
-
 sub read_pmg_mynetworks {
     my ($filename, $fh) = @_;
 
@@ -866,6 +896,12 @@ PVE::INotify::register_file('mynetworks', $mynetworks_filename,
                            \&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 {
@@ -971,31 +1007,51 @@ sub get_template_vars {
 
     my $nodename = PVE::INotify::nodename();
     my $int_ip = PMG::Cluster::remote_node_ip($nodename);
-    my $int_net_cidr = PMG::Utils::find_local_network_for_ip($int_ip);
     $vars->{ipconfig}->{int_ip} = $int_ip;
-    # $vars->{ipconfig}->{int_net_cidr} = $int_net_cidr;
 
     my $transportnets = [];
 
-    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";
+    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;
-    push @$mynetworks, 'hash:/etc/pmg/mynetworks';
+
+    if (my $int_net_cidr = PMG::Utils::find_local_network_for_ip($int_ip, 1)) {
+       if ($int_net_cidr =~ m/^($IPV6RE)\/(\d+)$/) {
+           push @$mynetworks, "[$1]/$2";
+       } else {
+           push @$mynetworks, $int_net_cidr;
+       }
+    } else {
+       if ($int_ip =~ m/^$IPV6RE$/) {
+           push @$mynetworks, "[$int_ip]/128";
+       } else {
+           push @$mynetworks, "$int_ip/32";
+       }
+    }
 
     my $netlist = PVE::INotify::read_file('mynetworks');
+    foreach my $cidr (keys %$netlist) {
+       if ($cidr =~ m/^($IPV6RE)\/(\d+)$/) {
+           push @$mynetworks, "[$1]/$2";
+       } else {
+           push @$mynetworks, $cidr;
+       }
+    }
+
+    push @$mynetworks, @$transportnets;
+
     # add default relay to mynetworks
     if (my $relay = $self->get('mail', 'relay')) {
        if ($relay =~ m/^$IPV4RE$/) {
@@ -1009,16 +1065,30 @@ sub get_template_vars {
 
     $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;
 
+    if ($int_ip =~ m/^$IPV6RE$/) {
+        $vars->{postfix}->{int_ip} = "[$int_ip]";
+    } else {
+        $vars->{postfix}->{int_ip} = $int_ip;
+    }
+
     my $resolv = PVE::INotify::read_file('resolvconf');
     $vars->{dns}->{hostname} = $nodename;
-    $vars->{dns}->{domain} = $resolv->{search};
 
-    my $wlbr = "$nodename.$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"
     }
@@ -1292,10 +1362,6 @@ sub rewrite_config_postfix {
     my ($self, $rulecache) = @_;
 
     # make sure we have required files (else postfix start fails)
-    postmap_pmg_domains();
-    postmap_pmg_transport();
-    postmap_pmg_mynetworks();
-
     IO::File->new($transport_map_filename, 'a', 0644);
 
     my $changes = 0;
@@ -1313,9 +1379,13 @@ sub rewrite_config_postfix {
     $changes = 1 if $self->rewrite_config_file(
        'master.cf.in', '/etc/postfix/master.cf');
 
-    rewrite_postfix_whitelist($rulecache) if $rulecache;
+    # 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();
 
-    # fixme: rewrite_config_tls_policy ($class);
+    rewrite_postfix_whitelist($rulecache) if $rulecache;
 
     # make sure aliases.db is up to date
     system('/usr/bin/newaliases');