]> git.proxmox.com Git - pmg-api.git/blob - PMG/Config.pm
remove wrong my declaration
[pmg-api.git] / PMG / Config.pm
1 package PMG::Config::Base;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6
7 use PVE::Tools;
8 use PVE::JSONSchema qw(get_standard_option);
9 use PVE::SectionConfig;
10
11 use base qw(PVE::SectionConfig);
12
13 my $defaultData = {
14 propertyList => {
15 type => { description => "Section type." },
16 section => {
17 description => "Secion ID.",
18 type => 'string', format => 'pve-configid',
19 },
20 },
21 };
22
23 sub private {
24 return $defaultData;
25 }
26
27 sub format_section_header {
28 my ($class, $type, $sectionId) = @_;
29
30 if ($type eq 'ldap') {
31 $sectionId =~ s/^ldap_//;
32 return "$type: $sectionId\n";
33 } else {
34 return "section: $type\n";
35 }
36 }
37
38
39 sub parse_section_header {
40 my ($class, $line) = @_;
41
42 if ($line =~ m/^(ldap|section):\s*(\S+)\s*$/) {
43 my ($raw_type, $raw_id) = (lc($1), $2);
44 my $type = $raw_type eq 'section' ? $raw_id : $raw_type;
45 my $section_id = "${raw_type}_${raw_id}";
46 my $errmsg = undef; # set if you want to skip whole section
47 eval { PVE::JSONSchema::pve_verify_configid($raw_id); };
48 $errmsg = $@ if $@;
49 my $config = {}; # to return additional attributes
50 return ($type, $section_id, $errmsg, $config);
51 }
52 return undef;
53 }
54
55 package PMG::Config::Admin;
56
57 use strict;
58 use warnings;
59
60 use base qw(PMG::Config::Base);
61
62 sub type {
63 return 'admin';
64 }
65
66 sub properties {
67 return {
68 dailyreport => {
69 description => "Send daily reports.",
70 type => 'boolean',
71 default => 1,
72 },
73 demo => {
74 description => "Demo mode - do not start SMTP filter.",
75 type => 'boolean',
76 default => 0,
77 },
78 email => {
79 description => "Administrator E-Mail address.",
80 type => 'string', format => 'email',
81 default => 'admin@domain.tld',
82 },
83 proxyport => {
84 description => "HTTP proxy port.",
85 type => 'integer',
86 minimum => 1,
87 default => 8080,
88 },
89 proxyserver => {
90 description => "HTTP proxy server address.",
91 type => 'string',
92 },
93 proxyuser => {
94 description => "HTTP proxy user name.",
95 type => 'string',
96 },
97 proxypassword => {
98 description => "HTTP proxy password.",
99 type => 'string',
100 },
101 };
102 }
103
104 sub options {
105 return {
106 dailyreport => { optional => 1 },
107 demo => { optional => 1 },
108 proxyport => { optional => 1 },
109 proxyserver => { optional => 1 },
110 proxyuser => { optional => 1 },
111 proxypassword => { optional => 1 },
112 };
113 }
114
115 package PMG::Config::Spam;
116
117 use strict;
118 use warnings;
119
120 use base qw(PMG::Config::Base);
121
122 sub type {
123 return 'spam';
124 }
125
126 sub properties {
127 return {
128 languages => {
129 description => "This option is used to specify which languages are considered OK for incoming mail.",
130 type => 'string',
131 pattern => '(all|([a-z][a-z])+( ([a-z][a-z])+)*)',
132 default => 'all',
133 },
134 use_bayes => {
135 description => "Whether to use the naive-Bayesian-style classifier.",
136 type => 'boolean',
137 default => 1,
138 },
139 use_awl => {
140 description => "Use the Auto-Whitelist plugin.",
141 type => 'boolean',
142 default => 1,
143 },
144 use_razor => {
145 description => "Whether to use Razor2, if it is available.",
146 type => 'boolean',
147 default => 1,
148 },
149 use_ocr => {
150 description => "Enable OCR to scan pictures.",
151 type => 'boolean',
152 default => 0,
153 },
154 wl_bounce_relays => {
155 description => "Whitelist legitimate bounce relays.",
156 type => 'string',
157 },
158 bounce_score => {
159 description => "Additional score for bounce mails.",
160 type => 'integer',
161 minimum => 0,
162 maximum => 1000,
163 default => 0,
164 },
165 rbl_checks => {
166 description => "Enable real time blacklists (RBL) checks.",
167 type => 'boolean',
168 default => 1,
169 },
170 maxspamsize => {
171 description => "Maximum size of spam messages in bytes.",
172 type => 'integer',
173 minimum => 64,
174 default => 200*1024,
175 },
176 };
177 }
178
179 sub options {
180 return {
181 use_awl => { optional => 1 },
182 use_razor => { optional => 1 },
183 use_ocr => { optional => 1 },
184 wl_bounce_relays => { optional => 1 },
185 languages => { optional => 1 },
186 use_bayes => { optional => 1 },
187 bounce_score => { optional => 1 },
188 rbl_checks => { optional => 1 },
189 maxspamsize => { optional => 1 },
190 };
191 }
192
193 package PMG::Config::ClamAV;
194
195 use strict;
196 use warnings;
197
198 use base qw(PMG::Config::Base);
199
200 sub type {
201 return 'clamav';
202 }
203
204 sub properties {
205 return {
206 dbmirror => {
207 description => "ClamAV database mirror server.",
208 type => 'string',
209 default => 'database.clamav.net',
210 },
211 archiveblockencrypted => {
212 description => "Wether to block encrypted archives. Mark encrypted archives as viruses.",
213 type => 'boolean',
214 default => 0,
215 },
216 archivemaxrec => {
217 description => "Nested archives are scanned recursively, e.g. if a ZIP archive contains a TAR file, all files within it will also be scanned. This options specifies how deeply the process should be continued. Warning: setting this limit too high may result in severe damage to the system.",
218 type => 'integer',
219 minimum => 1,
220 default => 5,
221 },
222 archivemaxfiles => {
223 description => "Number of files to be scanned within an archive, a document, or any other kind of container. Warning: disabling this limit or setting it too high may result in severe damage to the system.",
224 type => 'integer',
225 minimum => 0,
226 default => 1000,
227 },
228 archivemaxsize => {
229 description => "Files larger than this limit won't be scanned.",
230 type => 'integer',
231 minimum => 1000000,
232 default => 25000000,
233 },
234 maxscansize => {
235 description => "Sets the maximum amount of data to be scanned for each input file.",
236 type => 'integer',
237 minimum => 1000000,
238 default => 100000000,
239 },
240 maxcccount => {
241 description => "This option sets the lowest number of Credit Card or Social Security numbers found in a file to generate a detect.",
242 type => 'integer',
243 minimum => 0,
244 default => 0,
245 },
246 };
247 }
248
249 sub options {
250 return {
251 archiveblockencrypted => { optional => 1 },
252 archivemaxrec => { optional => 1 },
253 archivemaxfiles => { optional => 1 },
254 archivemaxsize => { optional => 1 },
255 maxscansize => { optional => 1 },
256 dbmirror => { optional => 1 },
257 maxcccount => { optional => 1 },
258 };
259 }
260
261 package PMG::Config::LDAP;
262
263 use strict;
264 use warnings;
265
266 use base qw(PMG::Config::Base);
267
268 sub type {
269 return 'ldap';
270 }
271
272 sub properties {
273 return {
274 mode => {
275 description => "LDAP protocol mode ('ldap' or 'ldaps').",
276 type => 'string',
277 enum => ['ldap', 'ldaps'],
278 default => 'ldap',
279 },
280 };
281 }
282
283 sub options {
284 return {
285 mode => { optional => 1 },
286 };
287 }
288
289 package PMG::Config::Mail;
290
291 use strict;
292 use warnings;
293
294 use PVE::ProcFSTools;
295
296 use base qw(PMG::Config::Base);
297
298 sub type {
299 return 'mail';
300 }
301
302 my $physicalmem = 0;
303 sub physical_memory {
304
305 return $physicalmem if $physicalmem;
306
307 my $info = PVE::ProcFSTools::read_meminfo();
308 my $total = int($info->{memtotal} / (1024*1024));
309
310 return $total;
311 }
312
313 sub get_max_filters {
314 # estimate optimal number of filter servers
315
316 my $max_servers = 5;
317 my $servermem = 120;
318 my $memory = physical_memory();
319 my $add_servers = int(($memory - 512)/$servermem);
320 $max_servers += $add_servers if $add_servers > 0;
321 $max_servers = 40 if $max_servers > 40;
322
323 return $max_servers - 2;
324 }
325
326 sub get_max_smtpd {
327 # estimate optimal number of smtpd daemons
328
329 my $max_servers = 25;
330 my $servermem = 20;
331 my $memory = physical_memory();
332 my $add_servers = int(($memory - 512)/$servermem);
333 $max_servers += $add_servers if $add_servers > 0;
334 $max_servers = 100 if $max_servers > 100;
335 return $max_servers;
336 }
337
338
339 sub properties {
340 return {
341 relay => {
342 description => "The default mail delivery transport (incoming mails).",
343 type => 'string',
344 },
345 relayport => {
346 description => "SMTP port number for relay host.",
347 type => 'integer',
348 minimum => 1,
349 maximum => 65535,
350 default => 25,
351 },
352 relaynomx => {
353 description => "Disable MX lookups for default relay.",
354 type => 'boolean',
355 default => 0,
356 },
357 smarthost => {
358 description => "When set, all outgoing mails are deliverd to the specified smarthost.",
359 type => 'string',
360 },
361 banner => {
362 description => "ESMTP banner.",
363 type => 'string',
364 maxLength => 1024,
365 default => 'ESMTP Proxmox',
366 },
367 max_filters => {
368 description => "Maximum number of filter processes.",
369 type => 'integer',
370 minimum => 3,
371 maximum => 40,
372 default => get_max_filters(),
373 },
374 max_smtpd_in => {
375 description => "Maximum number of SMTP daemon processes (in).",
376 type => 'integer',
377 minimum => 3,
378 maximum => 100,
379 default => get_max_smtpd(),
380 },
381 max_smtpd_out => {
382 description => "Maximum number of SMTP daemon processes (out).",
383 type => 'integer',
384 minimum => 3,
385 maximum => 100,
386 default => get_max_smtpd(),
387 },
388 conn_count_limit => {
389 description => "How many simultaneous connections any client is allowed to make to this service. To disable this feature, specify a limit of 0.",
390 type => 'integer',
391 minimum => 0,
392 default => 50,
393 },
394 conn_rate_limit => {
395 description => "The maximal number of connection attempts any client is allowed to make to this service per minute. To disable this feature, specify a limit of 0.",
396 type => 'integer',
397 minimum => 0,
398 default => 0,
399 },
400 message_rate_limit => {
401 description => "The maximal number of message delivery requests that any client is allowed to make to this service per minute.To disable this feature, specify a limit of 0.",
402 type => 'integer',
403 minimum => 0,
404 default => 0,
405 },
406 hide_received => {
407 description => "Hide received header in outgoing mails.",
408 type => 'boolean',
409 default => 0,
410 },
411 maxsize => {
412 description => "Maximum email size. Larger mails are rejected.",
413 type => 'integer',
414 minimum => 1024,
415 default => 1024*1024*10,
416 },
417 dwarning => {
418 description => "SMTP delay warning time (in hours).",
419 type => 'integer',
420 minimum => 0,
421 default => 4,
422 },
423 use_rbl => {
424 description => "Use Realtime Blacklists.",
425 type => 'boolean',
426 default => 1,
427 },
428 tls => {
429 description => "Use TLS.",
430 type => 'boolean',
431 default => 0,
432 },
433 spf => {
434 description => "Use Sender Policy Framework.",
435 type => 'boolean',
436 default => 1,
437 },
438 greylist => {
439 description => "Use Greylisting.",
440 type => 'boolean',
441 default => 1,
442 },
443 helotests => {
444 description => "Use SMTP HELO tests.",
445 type => 'boolean',
446 default => 0,
447 },
448 rejectunknown => {
449 description => "Reject unknown clients.",
450 type => 'boolean',
451 default => 0,
452 },
453 rejectunknownsender => {
454 description => "Reject unknown senders.",
455 type => 'boolean',
456 default => 0,
457 },
458 verifyreceivers => {
459 description => "Enable receiver verification. The value (if greater than 0) spefifies the numerical reply code when the Postfix SMTP server rejects a recipient address (450 or 550).",
460 type => 'integer',
461 minimum => 0,
462 maximum => 599,
463 default => 0,
464 },
465 dnsbl_sites => {
466 description => "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).",
467 type => 'string',
468 },
469 };
470 }
471
472 sub options {
473 return {
474 relay => { optional => 1 },
475 relayport => { optional => 1 },
476 relaynomx => { optional => 1 },
477 dwarning => { optional => 1 },
478 max_smtpd_in => { optional => 1 },
479 max_smtpd_out => { optional => 1 },
480 greylist => { optional => 1 },
481 helotests => { optional => 1 },
482 use_rbl => { optional => 1 },
483 tls => { optional => 1 },
484 spf => { optional => 1 },
485 maxsize => { optional => 1 },
486 banner => { optional => 1 },
487 max_filters => { optional => 1 },
488 hide_received => { optional => 1 },
489 rejectunknown => { optional => 1 },
490 rejectunknownsender => { optional => 1 },
491 conn_count_limit => { optional => 1 },
492 conn_rate_limit => { optional => 1 },
493 message_rate_limit => { optional => 1 },
494 verifyreceivers => { optional => 1 },
495 dnsbl_sites => { optional => 1 },
496 };
497 }
498 package PMG::Config;
499
500 use strict;
501 use warnings;
502 use IO::File;
503 use Data::Dumper;
504 use Template;
505
506 use PVE::SafeSyslog;
507 use PVE::Tools;
508 use PVE::INotify;
509
510 use PMG::AtomicFile;
511
512 PMG::Config::Admin->register();
513 PMG::Config::Mail->register();
514 PMG::Config::Spam->register();
515 PMG::Config::LDAP->register();
516 PMG::Config::ClamAV->register();
517
518 # initialize all plugins
519 PMG::Config::Base->init();
520
521
522 sub new {
523 my ($type) = @_;
524
525 my $class = ref($type) || $type;
526
527 my $cfg = PVE::INotify::read_file("pmg.conf");
528
529 return bless $cfg, $class;
530 }
531
532 sub write {
533 my ($self) = @_;
534
535 PVE::INotify::write_file("pmg.conf", $self);
536 }
537
538 my $lockfile = "/var/lock/pmgconfig.lck";
539
540 sub lock_config {
541 my ($code, $errmsg) = @_;
542
543 my $p = PVE::Tools::lock_file($lockfile, undef, $code);
544 if (my $err = $@) {
545 $errmsg ? die "$errmsg: $err" : die $err;
546 }
547 }
548
549 # set section values
550 # this does not work for ldap entries
551 sub set {
552 my ($self, $section, $key, $value) = @_;
553
554 my $pdata = PMG::Config::Base->private();
555
556 die "internal error" if $section eq 'ldap';
557
558 my $plugin = $pdata->{plugins}->{$section};
559 die "no such section '$section'" if !$plugin;
560
561 my $configid = "section_$section";
562 if (defined($value)) {
563 my $tmp = PMG::Config::Base->check_value($section, $key, $value, $section, 0);
564 print Dumper($self->{ids});
565 $self->{ids}->{$configid} = { type => $section } if !defined($self->{ids}->{$configid});
566 $self->{ids}->{$configid}->{$key} = PMG::Config::Base->decode_value($section, $key, $tmp);
567 } else {
568 if (defined($self->{ids}->{$configid})) {
569 delete $self->{ids}->{$configid}->{$key};
570 }
571 }
572
573 return undef;
574 }
575
576 # get section value or default
577 # this does not work for ldap entries
578 sub get {
579 my ($self, $section, $key) = @_;
580
581 my $pdata = PMG::Config::Base->private();
582 return undef if !defined($pdata->{options}->{$section});
583 return undef if !defined($pdata->{options}->{$section}->{$key});
584 my $pdesc = $pdata->{propertyList}->{$key};
585 return undef if !defined($pdesc);
586
587 my $configid = "section_$section";
588 if (defined($self->{ids}->{$configid}) &&
589 defined(my $value = $self->{ids}->{$configid}->{$key})) {
590 return $value;
591 }
592
593 return $pdesc->{default};
594 }
595
596 # get a whole section with default value
597 # this does not work for ldap entries
598 sub get_section {
599 my ($self, $section) = @_;
600
601 my $pdata = PMG::Config::Base->private();
602 return undef if !defined($pdata->{options}->{$section});
603
604 my $res = {};
605
606 foreach my $key (keys %{$pdata->{options}->{$section}}) {
607
608 my $pdesc = $pdata->{propertyList}->{$key};
609
610 my $configid = "section_$section";
611 if (defined($self->{ids}->{$configid}) &&
612 defined(my $value = $self->{ids}->{$configid}->{$key})) {
613 $res->{$key} = $value;
614 next;
615 }
616 $res->{$key} = $pdesc->{default};
617 }
618
619 return $res;
620 }
621
622 # get a whole config with default values
623 # this does not work for ldap entries
624 sub get_config {
625 my ($self) = @_;
626
627 my $pdata = PMG::Config::Base->private();
628
629 my $res = {};
630
631 foreach my $type (keys %{$pdata->{plugins}}) {
632 next if $type eq 'ldap';
633 my $plugin = $pdata->{plugins}->{$type};
634 $res->{$type} = $self->get_section($type);
635 }
636
637 return $res;
638 }
639
640 sub read_pmg_conf {
641 my ($filename, $fh) = @_;
642
643 local $/ = undef; # slurp mode
644
645 my $raw = <$fh>;
646
647 return PMG::Config::Base->parse_config($filename, $raw);
648 }
649
650 sub write_pmg_conf {
651 my ($filename, $fh, $cfg) = @_;
652
653 my $raw = PMG::Config::Base->write_config($filename, $cfg);
654
655 PVE::Tools::safe_print($filename, $fh, $raw);
656 }
657
658 PVE::INotify::register_file('pmg.conf', "/etc/proxmox/pmg.conf",
659 \&read_pmg_conf,
660 \&write_pmg_conf);
661
662 # parsers/writers for other files
663
664 my $domainsfilename = "/etc/proxmox/domains";
665
666 sub read_pmg_domains {
667 my ($filename, $fh) = @_;
668
669 my $domains = [];
670
671 if (defined($fh)) {
672 while (defined(my $line = <$fh>)) {
673 if ($line =~ m/^\s*(\S+)\s*$/) {
674 my $domain = $1;
675 push @$domains, $domain;
676 }
677 }
678 }
679
680 return $domains;
681 }
682
683 sub write_pmg_domains {
684 my ($filename, $fh, $domain) = @_;
685
686 foreach my $domain (sort @$domain) {
687 PVE::Tools::safe_print($filename, $fh, "$domain\n");
688 }
689 }
690
691 PVE::INotify::register_file('domains', $domainsfilename,
692 \&read_pmg_domains,
693 \&write_pmg_domains,
694 undef, always_call_parser => 1);
695
696 my $transport_map_filename = "/etc/postfix/transport";
697
698 sub read_transport_map {
699 my ($filename, $fh) = @_;
700
701 return [] if !defined($fh);
702
703 my $res = {};
704
705 while (defined(my $line = <$fh>)) {
706 chomp $line;
707 next if $line =~ m/^\s*$/;
708 next if $line =~ m/^\s*\#/;
709
710 if ($line =~ m/^(\S+)\s+smtp:([^\s:]+):(\d+)\s*$/) {
711 my $domain = $1;
712 my $host = $2;
713 my $port =$3;
714 my $nomx;
715
716 if ($host =~ m/^\[(.*)\]$/) {
717 $host = $1;
718 $nomx = 1;
719 }
720
721 my $key = "$host:$port";
722
723 $res->{$key}->{nomx} = $nomx;
724 $res->{$key}->{host} = $host;
725 $res->{$key}->{port} = $port;
726 $res->{$key}->{transport} = $key;
727
728 push @{$res->{$key}->{domains}}, $domain;
729 }
730 }
731
732 my $ta = [];
733
734 foreach my $t (sort keys %$res) {
735 push @$ta, $res->{$t};
736 }
737
738 return $ta;
739 }
740
741 sub write_ransport_map {
742 my ($filename, $fh, $tmap) = @_;
743
744 return if !$tmap;
745
746 foreach my $t (sort { $a->{transport} cmp $b->{transport} } @$tmap) {
747 my $domains = $t->{domains};
748
749 foreach my $d (sort @$domains) {
750 if ($t->{nomx}) {
751 PVE::Tools::safe_print($filename, $fh, "$d smtp:[$t->{host}]:$t->{port}\n");
752 } else {
753 PVE::Tools::safe_print($filename, $fh, "$d smtp:$t->{host}:$t->{port}\n");
754 }
755 }
756 }
757 }
758
759 PVE::INotify::register_file('transport', $transport_map_filename,
760 \&read_transport_map,
761 \&write_ransport_map,
762 undef, always_call_parser => 1);
763
764 # config file generation using templates
765
766 sub rewrite_config_file {
767 my ($self, $tmplname, $dstfn) = @_;
768
769 my $demo = $self->get('admin', 'demo');
770
771 my $srcfn = ($tmplname =~ m|^.?/|) ?
772 $tmplname : "/var/lib/pmg/templates/$tmplname";
773
774 if ($demo) {
775 my $demosrc = "$srcfn.demo";
776 $srcfn = $demosrc if -f $demosrc;
777 }
778
779 my $srcfd = IO::File->new ($srcfn, "r")
780 || die "cant read template '$srcfn' - $!: ERROR";
781 my $dstfd = PMG::AtomicFile->open ($dstfn, "w")
782 || die "cant open config file '$dstfn' - $!: ERROR";
783
784 if ($dstfn eq '/etc/fetchmailrc') {
785 my ($login, $pass, $uid, $gid) = getpwnam('fetchmail');
786 if ($uid && $gid) {
787 chown($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
788 }
789 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
790 } elsif ($dstfn eq '/etc/clamav/freshclam.conf') {
791 # needed if file contains a HTTPProxyPasswort
792
793 my $uid = getpwnam('clamav');
794 my $gid = getgrnam('adm');
795
796 if ($uid && $gid) {
797 chown ($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
798 }
799 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
800 }
801
802 my $template = Template->new({});
803
804 my $vars = { pmg => $self->get_config() };
805
806 my $nodename = PVE::INotify::nodename();
807 my $int_ip = PMG::Cluster::remote_node_ip($nodename);
808 my $int_net_cidr = PMG::Utils::find_local_network_for_ip($int_ip);
809
810 $vars->{ipconfig}->{int_ip} = $int_ip;
811 # $vars->{ipconfig}->{int_net_cidr} = $int_net_cidr;
812 $vars->{ipconfig}->{int_port} = 26;
813 $vars->{ipconfig}->{ext_port} = 25;
814
815 my $transportnets = []; # fixme
816 $vars->{postfix}->{transportnets} = join(' ', @$transportnets);
817
818 my $mynetworks = [ '127.0.0.0/8', '[::1]/128' ];
819 push @$mynetworks, @$transportnets;
820 push @$mynetworks, $int_net_cidr;
821
822 # add default relay to mynetworks
823 if (my $relay = $self->get('mail', 'relay')) {
824 if (Net::IP::ip_is_ipv4($relay)) {
825 push @$mynetworks, "$relay/32";
826 } elsif (Net::IP::ip_is_ipv6($relay)) {
827 push @$mynetworks, "[$relay]/128";
828 } else {
829 warn "unable to detect IP version of relay '$relay'";
830 }
831 }
832
833 $vars->{postfix}->{mynetworks} = join(' ', @$mynetworks);
834
835 my $usepolicy = 0;
836 $usepolicy = 1 if $self->get('mail', 'greylist') ||
837 $self->get('mail', 'spf') || $self->get('mail', 'use_rbl');
838 $vars->{postfix}->{usepolicy} = $usepolicy;
839
840 my $resolv = PVE::INotify::read_file('resolvconf');
841 $vars->{dns}->{hostname} = $nodename;
842 $vars->{dns}->{domain} = $resolv->{search};
843
844 $template->process($srcfd, $vars, $dstfd) ||
845 die $template->error();
846
847 $srcfd->close();
848 $dstfd->close (1);
849 }
850
851 sub rewrite_config_script {
852 my ($self, $tmplname, $dstfn) = @_;
853
854 $self->rewrite_config_file($tmplname, $dstfn);
855 system("chmod +x $dstfn");
856 }
857
858 # rewrite spam configuration
859 sub rewrite_config_spam {
860 my ($self) = @_;
861
862 my $use_awl = $self->get('spam', 'use_awl');
863 my $use_bayes = $self->get('spam', 'use_bayes');
864 my $use_razor = $self->get('spam', 'use_razor');
865
866 # delete AW and bayes databases if those features are disabled
867 unlink '/root/.spamassassin/auto-whitelist' if !$use_awl;
868 if (!$use_bayes) {
869 unlink '/root/.spamassassin/bayes_journal';
870 unlink '/root/.spamassassin/bayes_seen';
871 unlink '/root/.spamassassin/bayes_toks';
872 }
873
874 # make sure we have a custom.cf file (else cluster sync fails)
875 IO::File->new('/etc/mail/spamassassin/custom.cf', 'a', 0644);
876
877 $self->rewrite_config_file('local.cf.in', '/etc/mail/spamassassin/local.cf');
878 $self->rewrite_config_file('init.pre.in', '/etc/mail/spamassassin/init.pre');
879 $self->rewrite_config_file('v310.pre.in', '/etc/mail/spamassassin/v310.pre');
880 $self->rewrite_config_file('v320.pre.in', '/etc/mail/spamassassin/v320.pre');
881
882 if ($use_razor) {
883 mkdir "/root/.razor";
884 $self->rewrite_config_file('razor-agent.conf.in', '/root/.razor/razor-agent.conf');
885 if (! -e '/root/.razor/identity') {
886 eval {
887 my $timeout = 30;
888 PVE::Tools::run_command (['razor-admin', '-discover'], timeout => $timeout);
889 PVE::Tools::run_command (['razor-admin', '-register'], timeout => $timeout);
890 };
891 my $err = $@;
892 syslog('info', msgquote ("registering razor failed: $err")) if $err;
893 }
894 }
895 }
896
897 # rewrite ClamAV configuration
898 sub rewrite_config_clam {
899 my ($self) = @_;
900
901 $self->rewrite_config_file('clamd.conf.in', '/etc/clamav/clamd.conf');
902 $self->rewrite_config_file('freshclam.conf.in', '/etc/clamav/freshclam.conf');
903 }
904
905 sub rewrite_config_postgres {
906 my ($self) = @_;
907
908 my $pgconfdir = "/etc/postgresql/9.6/main";
909
910 $self->rewrite_config_file('pg_hba.conf.in', "$pgconfdir/pg_hba.conf");
911 $self->rewrite_config_file('postgresql.conf.in', "$pgconfdir/postgresql.conf");
912 }
913
914 # rewrite /root/.forward
915 sub rewrite_dot_forward {
916 my ($self) = @_;
917
918 my $fname = '/root/.forward';
919
920 my $email = $self->get('administration', 'email');
921 open(TMP, ">$fname");
922 if ($email && $email =~ m/\s*(\S+)\s*/) {
923 print (TMP "$1\n");
924 } else {
925 # empty .forward does not forward mails (see man local)
926 }
927 close (TMP);
928 }
929
930 # rewrite /etc/postfix/*
931 sub rewrite_config_postfix {
932 my ($self) = @_;
933
934 # make sure we have required files (else postfix start fails)
935 IO::File->new($domainsfilename, 'a', 0644);
936 IO::File->new($transport_map_filename, 'a', 0644);
937
938 if ($self->get('mail', 'tls')) {
939 eval {
940 my $resolv = PVE::INotify::read_file('resolvconf');
941 my $domain = $resolv->{search};
942
943 my $company = $domain; # what else ?
944 my $cn = "*.$domain";
945 PMG::Utils::gen_proxmox_tls_cert(0, $company, $cn);
946 };
947 syslog ('info', msgquote ("generating certificate failed: $@")) if $@;
948 }
949
950 $self->rewrite_config_file('main.cf.in', '/etc/postfix/main.cf');
951 $self->rewrite_config_file('master.cf.in', '/etc/postfix/master.cf');
952 #rewrite_config_transports ($class);
953 #rewrite_config_whitelist ($class);
954 #rewrite_config_tls_policy ($class);
955
956 # make sure aliases.db is up to date
957 system('/usr/bin/newaliases');
958 }
959
960 sub rewrite_config {
961 my ($self) = @_;
962
963 $self->rewrite_config_postfix();
964 $self->rewrite_dot_forward();
965 $self->rewrite_config_postgres();
966 $self->rewrite_config_spam();
967 $self->rewrite_config_clam();
968
969 }
970
971 1;