]> git.proxmox.com Git - pmg-api.git/blame - PMG/Config.pm
remove wrong my declaration
[pmg-api.git] / PMG / Config.pm
CommitLineData
7e0e6dbe
DM
1package PMG::Config::Base;
2
3use strict;
4use warnings;
5use Data::Dumper;
6
7use PVE::Tools;
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::SectionConfig;
10
11use base qw(PVE::SectionConfig);
12
13my $defaultData = {
14 propertyList => {
15 type => { description => "Section type." },
ef6f5dd1 16 section => {
7e0e6dbe
DM
17 description => "Secion ID.",
18 type => 'string', format => 'pve-configid',
19 },
20 },
21};
22
23sub private {
24 return $defaultData;
25}
26
27sub 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
39sub 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
ac5d1312 55package PMG::Config::Admin;
7e0e6dbe
DM
56
57use strict;
58use warnings;
59
60use base qw(PMG::Config::Base);
61
62sub type {
ac5d1312 63 return 'admin';
7e0e6dbe
DM
64}
65
66sub properties {
67 return {
68 dailyreport => {
69 description => "Send daily reports.",
70 type => 'boolean',
71 default => 1,
72 },
f62194b2
DM
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',
ac5d1312
DM
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 },
7e0e6dbe
DM
101 };
102}
103
104sub options {
105 return {
106 dailyreport => { optional => 1 },
f62194b2 107 demo => { optional => 1 },
ac5d1312
DM
108 proxyport => { optional => 1 },
109 proxyserver => { optional => 1 },
110 proxyuser => { optional => 1 },
111 proxypassword => { optional => 1 },
7e0e6dbe
DM
112 };
113}
114
115package PMG::Config::Spam;
116
117use strict;
118use warnings;
119
120use base qw(PMG::Config::Base);
121
122sub type {
123 return 'spam';
124}
125
126sub properties {
127 return {
1ccc8e95
DM
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 },
582cfacf
DM
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 },
03ac6d8f
DM
149 use_ocr => {
150 description => "Enable OCR to scan pictures.",
151 type => 'boolean',
152 default => 0,
153 },
1ccc8e95
DM
154 wl_bounce_relays => {
155 description => "Whitelist legitimate bounce relays.",
156 type => 'string',
157 },
7e0e6dbe
DM
158 bounce_score => {
159 description => "Additional score for bounce mails.",
160 type => 'integer',
161 minimum => 0,
162 maximum => 1000,
163 default => 0,
164 },
f62194b2
DM
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',
4d76e24e 173 minimum => 64,
f62194b2
DM
174 default => 200*1024,
175 },
7e0e6dbe
DM
176 };
177}
178
179sub options {
180 return {
582cfacf
DM
181 use_awl => { optional => 1 },
182 use_razor => { optional => 1 },
03ac6d8f 183 use_ocr => { optional => 1 },
1ccc8e95
DM
184 wl_bounce_relays => { optional => 1 },
185 languages => { optional => 1 },
186 use_bayes => { optional => 1 },
7e0e6dbe 187 bounce_score => { optional => 1 },
f62194b2
DM
188 rbl_checks => { optional => 1 },
189 maxspamsize => { optional => 1 },
190 };
191}
192
193package PMG::Config::ClamAV;
194
195use strict;
196use warnings;
197
198use base qw(PMG::Config::Base);
199
200sub type {
201 return 'clamav';
202}
203
204sub properties {
205 return {
ac5d1312
DM
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.",
1baec5ab 218 type => 'integer',
ac5d1312
DM
219 minimum => 1,
220 default => 5,
221 },
f62194b2 222 archivemaxfiles => {
ac5d1312 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.",
f62194b2
DM
224 type => 'integer',
225 minimum => 0,
226 default => 1000,
227 },
ac5d1312
DM
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 },
f62194b2
DM
246 };
247}
248
249sub options {
250 return {
ac5d1312
DM
251 archiveblockencrypted => { optional => 1 },
252 archivemaxrec => { optional => 1 },
f62194b2 253 archivemaxfiles => { optional => 1 },
ac5d1312
DM
254 archivemaxsize => { optional => 1 },
255 maxscansize => { optional => 1 },
256 dbmirror => { optional => 1 },
257 maxcccount => { optional => 1 },
7e0e6dbe
DM
258 };
259}
260
261package PMG::Config::LDAP;
262
263use strict;
264use warnings;
265
266use base qw(PMG::Config::Base);
267
268sub type {
269 return 'ldap';
270}
271
272sub 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
283sub options {
284 return {
285 mode => { optional => 1 },
286 };
287}
f62194b2 288
d9dc3c08
DM
289package PMG::Config::Mail;
290
291use strict;
292use warnings;
293
f62194b2
DM
294use PVE::ProcFSTools;
295
d9dc3c08
DM
296use base qw(PMG::Config::Base);
297
298sub type {
299 return 'mail';
300}
301
f62194b2
DM
302my $physicalmem = 0;
303sub 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
313sub 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
f609bf7f
DM
326sub 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
d9dc3c08
DM
339sub properties {
340 return {
f609bf7f
DM
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 },
d9dc3c08
DM
361 banner => {
362 description => "ESMTP banner.",
363 type => 'string',
364 maxLength => 1024,
365 default => 'ESMTP Proxmox',
366 },
f62194b2
DM
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 },
f609bf7f
DM
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 },
f62194b2
DM
406 hide_received => {
407 description => "Hide received header in outgoing mails.",
408 type => 'boolean',
ac5d1312
DM
409 default => 0,
410 },
f609bf7f 411 maxsize => {
ac5d1312
DM
412 description => "Maximum email size. Larger mails are rejected.",
413 type => 'integer',
414 minimum => 1024,
415 default => 1024*1024*10,
f62194b2 416 },
f609bf7f
DM
417 dwarning => {
418 description => "SMTP delay warning time (in hours).",
419 type => 'integer',
420 minimum => 0,
421 default => 4,
422 },
423 use_rbl => {
4d76e24e 424 description => "Use Realtime Blacklists.",
f609bf7f
DM
425 type => 'boolean',
426 default => 1,
427 },
428 tls => {
4d76e24e 429 description => "Use TLS.",
f609bf7f
DM
430 type => 'boolean',
431 default => 0,
432 },
433 spf => {
4d76e24e 434 description => "Use Sender Policy Framework.",
f609bf7f
DM
435 type => 'boolean',
436 default => 1,
437 },
438 greylist => {
4d76e24e 439 description => "Use Greylisting.",
f609bf7f
DM
440 type => 'boolean',
441 default => 1,
442 },
443 helotests => {
4d76e24e 444 description => "Use SMTP HELO tests.",
f609bf7f
DM
445 type => 'boolean',
446 default => 0,
447 },
448 rejectunknown => {
4d76e24e 449 description => "Reject unknown clients.",
f609bf7f
DM
450 type => 'boolean',
451 default => 0,
452 },
453 rejectunknownsender => {
4d76e24e 454 description => "Reject unknown senders.",
f609bf7f
DM
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 },
d9dc3c08
DM
469 };
470}
471
472sub options {
473 return {
f609bf7f
DM
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 },
d9dc3c08 486 banner => { optional => 1 },
f62194b2
DM
487 max_filters => { optional => 1 },
488 hide_received => { optional => 1 },
f609bf7f
DM
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 },
d9dc3c08
DM
496 };
497}
7e0e6dbe
DM
498package PMG::Config;
499
500use strict;
501use warnings;
9123cab5 502use IO::File;
7e0e6dbe 503use Data::Dumper;
4ccdc564 504use Template;
7e0e6dbe 505
9123cab5 506use PVE::SafeSyslog;
7e0e6dbe
DM
507use PVE::Tools;
508use PVE::INotify;
509
4ccdc564
DM
510use PMG::AtomicFile;
511
ac5d1312 512PMG::Config::Admin->register();
d9dc3c08 513PMG::Config::Mail->register();
7e0e6dbe
DM
514PMG::Config::Spam->register();
515PMG::Config::LDAP->register();
f62194b2 516PMG::Config::ClamAV->register();
7e0e6dbe
DM
517
518# initialize all plugins
519PMG::Config::Base->init();
520
f62194b2
DM
521
522sub 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
be6e2db9
DM
532sub write {
533 my ($self) = @_;
534
535 PVE::INotify::write_file("pmg.conf", $self);
536}
537
f21d933c
DM
538my $lockfile = "/var/lock/pmgconfig.lck";
539
540sub 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
062f0498
DM
549# set section values
550# this does not work for ldap entries
551sub 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
f62194b2
DM
576# get section value or default
577# this does not work for ldap entries
578sub 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;
1ccc8e95 591 }
f62194b2
DM
592
593 return $pdesc->{default};
594}
595
1ccc8e95
DM
596# get a whole section with default value
597# this does not work for ldap entries
598sub 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
be16be07
DM
622# get a whole config with default values
623# this does not work for ldap entries
624sub get_config {
625 my ($self) = @_;
626
9dab5fe5
DM
627 my $pdata = PMG::Config::Base->private();
628
be16be07
DM
629 my $res = {};
630
9dab5fe5
DM
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);
be16be07
DM
635 }
636
637 return $res;
638}
639
7e0e6dbe
DM
640sub read_pmg_conf {
641 my ($filename, $fh) = @_;
f62194b2 642
7e0e6dbe 643 local $/ = undef; # slurp mode
f62194b2 644
7e0e6dbe
DM
645 my $raw = <$fh>;
646
647 return PMG::Config::Base->parse_config($filename, $raw);
648}
649
650sub 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
f62194b2
DM
658PVE::INotify::register_file('pmg.conf', "/etc/proxmox/pmg.conf",
659 \&read_pmg_conf,
7e0e6dbe
DM
660 \&write_pmg_conf);
661
f609bf7f
DM
662# parsers/writers for other files
663
664my $domainsfilename = "/etc/proxmox/domains";
665
666sub 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
683sub 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
691PVE::INotify::register_file('domains', $domainsfilename,
692 \&read_pmg_domains,
693 \&write_pmg_domains,
694 undef, always_call_parser => 1);
695
3546daf0
DM
696my $transport_map_filename = "/etc/postfix/transport";
697
698sub 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
741sub 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
759PVE::INotify::register_file('transport', $transport_map_filename,
760 \&read_transport_map,
761 \&write_ransport_map,
762 undef, always_call_parser => 1);
7e0e6dbe 763
4ccdc564
DM
764# config file generation using templates
765
766sub 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
f609bf7f
DM
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
4ccdc564
DM
844 $template->process($srcfd, $vars, $dstfd) ||
845 die $template->error();
846
847 $srcfd->close();
848 $dstfd->close (1);
849}
850
851sub rewrite_config_script {
852 my ($self, $tmplname, $dstfn) = @_;
853
854 $self->rewrite_config_file($tmplname, $dstfn);
855 system("chmod +x $dstfn");
856}
857
9123cab5
DM
858# rewrite spam configuration
859sub 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
4ccdc564
DM
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');
9123cab5
DM
881
882 if ($use_razor) {
883 mkdir "/root/.razor";
4ccdc564 884 $self->rewrite_config_file('razor-agent.conf.in', '/root/.razor/razor-agent.conf');
9123cab5
DM
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
ac5d1312
DM
897# rewrite ClamAV configuration
898sub rewrite_config_clam {
899 my ($self) = @_;
900
4ccdc564
DM
901 $self->rewrite_config_file('clamd.conf.in', '/etc/clamav/clamd.conf');
902 $self->rewrite_config_file('freshclam.conf.in', '/etc/clamav/freshclam.conf');
ac5d1312
DM
903}
904
86737f12
DM
905sub 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
915sub 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
f609bf7f
DM
930# rewrite /etc/postfix/*
931sub rewrite_config_postfix {
932 my ($self) = @_;
933
3546daf0 934 # make sure we have required files (else postfix start fails)
f609bf7f 935 IO::File->new($domainsfilename, 'a', 0644);
3546daf0 936 IO::File->new($transport_map_filename, 'a', 0644);
f609bf7f
DM
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
f983300f
DM
960sub rewrite_config {
961 my ($self) = @_;
962
f609bf7f 963 $self->rewrite_config_postfix();
86737f12
DM
964 $self->rewrite_dot_forward();
965 $self->rewrite_config_postgres();
f983300f
DM
966 $self->rewrite_config_spam();
967 $self->rewrite_config_clam();
f609bf7f 968
f983300f
DM
969}
970
7e0e6dbe 9711;