]> git.proxmox.com Git - pmg-api.git/blob - PMG/Config.pm
implement more configuration properies and templates
[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_id => {
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 minimim => 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 minimum => 1,
219 default => 5,
220 },
221 archivemaxfiles => {
222 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.",
223 type => 'integer',
224 minimum => 0,
225 default => 1000,
226 },
227 archivemaxsize => {
228 description => "Files larger than this limit won't be scanned.",
229 type => 'integer',
230 minimum => 1000000,
231 default => 25000000,
232 },
233 maxscansize => {
234 description => "Sets the maximum amount of data to be scanned for each input file.",
235 type => 'integer',
236 minimum => 1000000,
237 default => 100000000,
238 },
239 maxcccount => {
240 description => "This option sets the lowest number of Credit Card or Social Security numbers found in a file to generate a detect.",
241 type => 'integer',
242 minimum => 0,
243 default => 0,
244 },
245 };
246 }
247
248 sub options {
249 return {
250 archiveblockencrypted => { optional => 1 },
251 archivemaxrec => { optional => 1 },
252 archivemaxfiles => { optional => 1 },
253 archivemaxsize => { optional => 1 },
254 maxscansize => { optional => 1 },
255 dbmirror => { optional => 1 },
256 maxcccount => { optional => 1 },
257 };
258 }
259
260 package PMG::Config::LDAP;
261
262 use strict;
263 use warnings;
264
265 use base qw(PMG::Config::Base);
266
267 sub type {
268 return 'ldap';
269 }
270
271 sub properties {
272 return {
273 mode => {
274 description => "LDAP protocol mode ('ldap' or 'ldaps').",
275 type => 'string',
276 enum => ['ldap', 'ldaps'],
277 default => 'ldap',
278 },
279 };
280 }
281
282 sub options {
283 return {
284 mode => { optional => 1 },
285 };
286 }
287
288 package PMG::Config::Mail;
289
290 use strict;
291 use warnings;
292
293 use PVE::ProcFSTools;
294
295 use base qw(PMG::Config::Base);
296
297 sub type {
298 return 'mail';
299 }
300
301 my $physicalmem = 0;
302 sub physical_memory {
303
304 return $physicalmem if $physicalmem;
305
306 my $info = PVE::ProcFSTools::read_meminfo();
307 my $total = int($info->{memtotal} / (1024*1024));
308
309 return $total;
310 }
311
312 sub get_max_filters {
313 # estimate optimal number of filter servers
314
315 my $max_servers = 5;
316 my $servermem = 120;
317 my $memory = physical_memory();
318 my $add_servers = int(($memory - 512)/$servermem);
319 $max_servers += $add_servers if $add_servers > 0;
320 $max_servers = 40 if $max_servers > 40;
321
322 return $max_servers - 2;
323 }
324
325 sub get_max_smtpd {
326 # estimate optimal number of smtpd daemons
327
328 my $max_servers = 25;
329 my $servermem = 20;
330 my $memory = physical_memory();
331 my $add_servers = int(($memory - 512)/$servermem);
332 $max_servers += $add_servers if $add_servers > 0;
333 $max_servers = 100 if $max_servers > 100;
334 return $max_servers;
335 }
336
337
338 sub properties {
339 return {
340 relay => {
341 description => "The default mail delivery transport (incoming mails).",
342 type => 'string',
343 },
344 relayport => {
345 description => "SMTP port number for relay host.",
346 type => 'integer',
347 minimum => 1,
348 maximum => 65535,
349 default => 25,
350 },
351 relaynomx => {
352 description => "Disable MX lookups for default relay.",
353 type => 'boolean',
354 default => 0,
355 },
356 smarthost => {
357 description => "When set, all outgoing mails are deliverd to the specified smarthost.",
358 type => 'string',
359 },
360 banner => {
361 description => "ESMTP banner.",
362 type => 'string',
363 maxLength => 1024,
364 default => 'ESMTP Proxmox',
365 },
366 max_filters => {
367 description => "Maximum number of filter processes.",
368 type => 'integer',
369 minimum => 3,
370 maximum => 40,
371 default => get_max_filters(),
372 },
373 max_smtpd_in => {
374 description => "Maximum number of SMTP daemon processes (in).",
375 type => 'integer',
376 minimum => 3,
377 maximum => 100,
378 default => get_max_smtpd(),
379 },
380 max_smtpd_out => {
381 description => "Maximum number of SMTP daemon processes (out).",
382 type => 'integer',
383 minimum => 3,
384 maximum => 100,
385 default => get_max_smtpd(),
386 },
387 conn_count_limit => {
388 description => "How many simultaneous connections any client is allowed to make to this service. To disable this feature, specify a limit of 0.",
389 type => 'integer',
390 minimum => 0,
391 default => 50,
392 },
393 conn_rate_limit => {
394 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.",
395 type => 'integer',
396 minimum => 0,
397 default => 0,
398 },
399 message_rate_limit => {
400 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.",
401 type => 'integer',
402 minimum => 0,
403 default => 0,
404 },
405 hide_received => {
406 description => "Hide received header in outgoing mails.",
407 type => 'boolean',
408 default => 0,
409 },
410 maxsize => {
411 description => "Maximum email size. Larger mails are rejected.",
412 type => 'integer',
413 minimum => 1024,
414 default => 1024*1024*10,
415 },
416 dwarning => {
417 description => "SMTP delay warning time (in hours).",
418 type => 'integer',
419 minimum => 0,
420 default => 4,
421 },
422 use_rbl => {
423 descriptions => "Use Realtime Blacklists.",
424 type => 'boolean',
425 default => 1,
426 },
427 tls => {
428 descriptions => "Use TLS.",
429 type => 'boolean',
430 default => 0,
431 },
432 spf => {
433 descriptions => "Use Sender Policy Framework.",
434 type => 'boolean',
435 default => 1,
436 },
437 greylist => {
438 descriptions => "Use Greylisting.",
439 type => 'boolean',
440 default => 1,
441 },
442 helotests => {
443 descriptions => "Use SMTP HELO tests.",
444 type => 'boolean',
445 default => 0,
446 },
447 rejectunknown => {
448 descriptions => "Reject unknown clients.",
449 type => 'boolean',
450 default => 0,
451 },
452 rejectunknownsender => {
453 descriptions => "Reject unknown senders.",
454 type => 'boolean',
455 default => 0,
456 },
457 verifyreceivers => {
458 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).",
459 type => 'integer',
460 minimum => 0,
461 maximum => 599,
462 default => 0,
463 },
464 dnsbl_sites => {
465 description => "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).",
466 type => 'string',
467 },
468 };
469 }
470
471 sub options {
472 return {
473 relay => { optional => 1 },
474 relayport => { optional => 1 },
475 relaynomx => { optional => 1 },
476 dwarning => { optional => 1 },
477 max_smtpd_in => { optional => 1 },
478 max_smtpd_out => { optional => 1 },
479 greylist => { optional => 1 },
480 helotests => { optional => 1 },
481 use_rbl => { optional => 1 },
482 tls => { optional => 1 },
483 spf => { optional => 1 },
484 maxsize => { optional => 1 },
485 banner => { optional => 1 },
486 max_filters => { optional => 1 },
487 hide_received => { optional => 1 },
488 rejectunknown => { optional => 1 },
489 rejectunknownsender => { optional => 1 },
490 conn_count_limit => { optional => 1 },
491 conn_rate_limit => { optional => 1 },
492 message_rate_limit => { optional => 1 },
493 verifyreceivers => { optional => 1 },
494 dnsbl_sites => { optional => 1 },
495 };
496 }
497 package PMG::Config;
498
499 use strict;
500 use warnings;
501 use IO::File;
502 use Data::Dumper;
503 use Template;
504
505 use PVE::SafeSyslog;
506 use PVE::Tools;
507 use PVE::INotify;
508
509 use PMG::AtomicFile;
510
511 PMG::Config::Admin->register();
512 PMG::Config::Mail->register();
513 PMG::Config::Spam->register();
514 PMG::Config::LDAP->register();
515 PMG::Config::ClamAV->register();
516
517 # initialize all plugins
518 PMG::Config::Base->init();
519
520
521 sub new {
522 my ($type) = @_;
523
524 my $class = ref($type) || $type;
525
526 my $cfg = PVE::INotify::read_file("pmg.conf");
527
528 return bless $cfg, $class;
529 }
530
531 # set section values
532 # this does not work for ldap entries
533 sub set {
534 my ($self, $section, $key, $value) = @_;
535
536 my $pdata = PMG::Config::Base->private();
537
538 die "internal error" if $section eq 'ldap';
539
540 my $plugin = $pdata->{plugins}->{$section};
541 die "no such section '$section'" if !$plugin;
542
543 my $configid = "section_$section";
544 if (defined($value)) {
545 my $tmp = PMG::Config::Base->check_value($section, $key, $value, $section, 0);
546 print Dumper($self->{ids});
547 $self->{ids}->{$configid} = { type => $section } if !defined($self->{ids}->{$configid});
548 $self->{ids}->{$configid}->{$key} = PMG::Config::Base->decode_value($section, $key, $tmp);
549 } else {
550 if (defined($self->{ids}->{$configid})) {
551 delete $self->{ids}->{$configid}->{$key};
552 }
553 }
554
555 return undef;
556 }
557
558 # get section value or default
559 # this does not work for ldap entries
560 sub get {
561 my ($self, $section, $key) = @_;
562
563 my $pdata = PMG::Config::Base->private();
564 return undef if !defined($pdata->{options}->{$section});
565 return undef if !defined($pdata->{options}->{$section}->{$key});
566 my $pdesc = $pdata->{propertyList}->{$key};
567 return undef if !defined($pdesc);
568
569 my $configid = "section_$section";
570 if (defined($self->{ids}->{$configid}) &&
571 defined(my $value = $self->{ids}->{$configid}->{$key})) {
572 return $value;
573 }
574
575 return $pdesc->{default};
576 }
577
578 # get a whole section with default value
579 # this does not work for ldap entries
580 sub get_section {
581 my ($self, $section) = @_;
582
583 my $pdata = PMG::Config::Base->private();
584 return undef if !defined($pdata->{options}->{$section});
585
586 my $res = {};
587
588 foreach my $key (keys %{$pdata->{options}->{$section}}) {
589
590 my $pdesc = $pdata->{propertyList}->{$key};
591
592 my $configid = "section_$section";
593 if (defined($self->{ids}->{$configid}) &&
594 defined(my $value = $self->{ids}->{$configid}->{$key})) {
595 $res->{$key} = $value;
596 next;
597 }
598 $res->{$key} = $pdesc->{default};
599 }
600
601 return $res;
602 }
603
604 # get a whole config with default values
605 # this does not work for ldap entries
606 sub get_config {
607 my ($self) = @_;
608
609 my $pdata = PMG::Config::Base->private();
610
611 my $res = {};
612
613 foreach my $type (keys %{$pdata->{plugins}}) {
614 next if $type eq 'ldap';
615 my $plugin = $pdata->{plugins}->{$type};
616 $res->{$type} = $self->get_section($type);
617 }
618
619 return $res;
620 }
621
622 sub read_pmg_conf {
623 my ($filename, $fh) = @_;
624
625 local $/ = undef; # slurp mode
626
627 my $raw = <$fh>;
628
629 return PMG::Config::Base->parse_config($filename, $raw);
630 }
631
632 sub write_pmg_conf {
633 my ($filename, $fh, $cfg) = @_;
634
635 my $raw = PMG::Config::Base->write_config($filename, $cfg);
636
637 PVE::Tools::safe_print($filename, $fh, $raw);
638 }
639
640 PVE::INotify::register_file('pmg.conf', "/etc/proxmox/pmg.conf",
641 \&read_pmg_conf,
642 \&write_pmg_conf);
643
644 # parsers/writers for other files
645
646 my $domainsfilename = "/etc/proxmox/domains";
647
648 sub read_pmg_domains {
649 my ($filename, $fh) = @_;
650
651 my $domains = [];
652
653 if (defined($fh)) {
654 while (defined(my $line = <$fh>)) {
655 if ($line =~ m/^\s*(\S+)\s*$/) {
656 my $domain = $1;
657 push @$domains, $domain;
658 }
659 }
660 }
661
662 return $domains;
663 }
664
665 sub write_pmg_domains {
666 my ($filename, $fh, $domain) = @_;
667
668 foreach my $domain (sort @$domain) {
669 PVE::Tools::safe_print($filename, $fh, "$domain\n");
670 }
671 }
672
673 PVE::INotify::register_file('domains', $domainsfilename,
674 \&read_pmg_domains,
675 \&write_pmg_domains,
676 undef, always_call_parser => 1);
677
678
679 # config file generation using templates
680
681 sub rewrite_config_file {
682 my ($self, $tmplname, $dstfn) = @_;
683
684 my $demo = $self->get('admin', 'demo');
685
686 my $srcfn = ($tmplname =~ m|^.?/|) ?
687 $tmplname : "/var/lib/pmg/templates/$tmplname";
688
689 if ($demo) {
690 my $demosrc = "$srcfn.demo";
691 $srcfn = $demosrc if -f $demosrc;
692 }
693
694 my $srcfd = IO::File->new ($srcfn, "r")
695 || die "cant read template '$srcfn' - $!: ERROR";
696 my $dstfd = PMG::AtomicFile->open ($dstfn, "w")
697 || die "cant open config file '$dstfn' - $!: ERROR";
698
699 if ($dstfn eq '/etc/fetchmailrc') {
700 my ($login, $pass, $uid, $gid) = getpwnam('fetchmail');
701 if ($uid && $gid) {
702 chown($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
703 }
704 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
705 } elsif ($dstfn eq '/etc/clamav/freshclam.conf') {
706 # needed if file contains a HTTPProxyPasswort
707
708 my $uid = getpwnam('clamav');
709 my $gid = getgrnam('adm');
710
711 if ($uid && $gid) {
712 chown ($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
713 }
714 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
715 }
716
717 my $template = Template->new({});
718
719 my $vars = { pmg => $self->get_config() };
720
721 my $nodename = PVE::INotify::nodename();
722 my $int_ip = PMG::Cluster::remote_node_ip($nodename);
723 my $int_net_cidr = PMG::Utils::find_local_network_for_ip($int_ip);
724
725 $vars->{ipconfig}->{int_ip} = $int_ip;
726 # $vars->{ipconfig}->{int_net_cidr} = $int_net_cidr;
727 $vars->{ipconfig}->{int_port} = 26;
728 $vars->{ipconfig}->{ext_port} = 25;
729
730 my $transportnets = []; # fixme
731 $vars->{postfix}->{transportnets} = join(' ', @$transportnets);
732
733 my $mynetworks = [ '127.0.0.0/8', '[::1]/128' ];
734 push @$mynetworks, @$transportnets;
735 push @$mynetworks, $int_net_cidr;
736
737 # add default relay to mynetworks
738 if (my $relay = $self->get('mail', 'relay')) {
739 if (Net::IP::ip_is_ipv4($relay)) {
740 push @$mynetworks, "$relay/32";
741 } elsif (Net::IP::ip_is_ipv6($relay)) {
742 push @$mynetworks, "[$relay]/128";
743 } else {
744 warn "unable to detect IP version of relay '$relay'";
745 }
746 }
747
748 $vars->{postfix}->{mynetworks} = join(' ', @$mynetworks);
749
750 my $usepolicy = 0;
751 $usepolicy = 1 if $self->get('mail', 'greylist') ||
752 $self->get('mail', 'spf') || $self->get('mail', 'use_rbl');
753 $vars->{postfix}->{usepolicy} = $usepolicy;
754
755 my $resolv = PVE::INotify::read_file('resolvconf');
756 $vars->{dns}->{hostname} = $nodename;
757 $vars->{dns}->{domain} = $resolv->{search};
758
759 $template->process($srcfd, $vars, $dstfd) ||
760 die $template->error();
761
762 $srcfd->close();
763 $dstfd->close (1);
764 }
765
766 sub rewrite_config_script {
767 my ($self, $tmplname, $dstfn) = @_;
768
769 $self->rewrite_config_file($tmplname, $dstfn);
770 system("chmod +x $dstfn");
771 }
772
773 # rewrite spam configuration
774 sub rewrite_config_spam {
775 my ($self) = @_;
776
777 my $use_awl = $self->get('spam', 'use_awl');
778 my $use_bayes = $self->get('spam', 'use_bayes');
779 my $use_razor = $self->get('spam', 'use_razor');
780
781 # delete AW and bayes databases if those features are disabled
782 unlink '/root/.spamassassin/auto-whitelist' if !$use_awl;
783 if (!$use_bayes) {
784 unlink '/root/.spamassassin/bayes_journal';
785 unlink '/root/.spamassassin/bayes_seen';
786 unlink '/root/.spamassassin/bayes_toks';
787 }
788
789 # make sure we have a custom.cf file (else cluster sync fails)
790 IO::File->new('/etc/mail/spamassassin/custom.cf', 'a', 0644);
791
792 $self->rewrite_config_file('local.cf.in', '/etc/mail/spamassassin/local.cf');
793 $self->rewrite_config_file('init.pre.in', '/etc/mail/spamassassin/init.pre');
794 $self->rewrite_config_file('v310.pre.in', '/etc/mail/spamassassin/v310.pre');
795 $self->rewrite_config_file('v320.pre.in', '/etc/mail/spamassassin/v320.pre');
796
797 if ($use_razor) {
798 mkdir "/root/.razor";
799 $self->rewrite_config_file('razor-agent.conf.in', '/root/.razor/razor-agent.conf');
800 if (! -e '/root/.razor/identity') {
801 eval {
802 my $timeout = 30;
803 PVE::Tools::run_command (['razor-admin', '-discover'], timeout => $timeout);
804 PVE::Tools::run_command (['razor-admin', '-register'], timeout => $timeout);
805 };
806 my $err = $@;
807 syslog('info', msgquote ("registering razor failed: $err")) if $err;
808 }
809 }
810 }
811
812 # rewrite ClamAV configuration
813 sub rewrite_config_clam {
814 my ($self) = @_;
815
816 $self->rewrite_config_file('clamd.conf.in', '/etc/clamav/clamd.conf');
817 $self->rewrite_config_file('freshclam.conf.in', '/etc/clamav/freshclam.conf');
818 }
819
820 sub rewrite_config_postgres {
821 my ($self) = @_;
822
823 my $pgconfdir = "/etc/postgresql/9.6/main";
824
825 $self->rewrite_config_file('pg_hba.conf.in', "$pgconfdir/pg_hba.conf");
826 $self->rewrite_config_file('postgresql.conf.in', "$pgconfdir/postgresql.conf");
827 }
828
829 # rewrite /root/.forward
830 sub rewrite_dot_forward {
831 my ($self) = @_;
832
833 my $fname = '/root/.forward';
834
835 my $email = $self->get('administration', 'email');
836 open(TMP, ">$fname");
837 if ($email && $email =~ m/\s*(\S+)\s*/) {
838 print (TMP "$1\n");
839 } else {
840 # empty .forward does not forward mails (see man local)
841 }
842 close (TMP);
843 }
844
845 # rewrite /etc/postfix/*
846 sub rewrite_config_postfix {
847 my ($self) = @_;
848
849 # make sure we have a domains file (else postfix start fails)
850 IO::File->new($domainsfilename, 'a', 0644);
851
852 if ($self->get('mail', 'tls')) {
853 eval {
854 my $resolv = PVE::INotify::read_file('resolvconf');
855 my $domain = $resolv->{search};
856
857 my $company = $domain; # what else ?
858 my $cn = "*.$domain";
859 PMG::Utils::gen_proxmox_tls_cert(0, $company, $cn);
860 };
861 syslog ('info', msgquote ("generating certificate failed: $@")) if $@;
862 }
863
864 $self->rewrite_config_file('main.cf.in', '/etc/postfix/main.cf');
865 $self->rewrite_config_file('master.cf.in', '/etc/postfix/master.cf');
866 #rewrite_config_transports ($class);
867 #rewrite_config_whitelist ($class);
868 #rewrite_config_tls_policy ($class);
869
870 # make sure aliases.db is up to date
871 system('/usr/bin/newaliases');
872 }
873
874 sub rewrite_config {
875 my ($self) = @_;
876
877 $self->rewrite_config_postfix();
878 $self->rewrite_dot_forward();
879 $self->rewrite_config_postgres();
880 $self->rewrite_config_spam();
881 $self->rewrite_config_clam();
882
883 }
884
885 1;