]>
Commit | Line | Data |
---|---|---|
7e0e6dbe DM |
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." }, | |
ef6f5dd1 | 16 | section => { |
7e0e6dbe DM |
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 | ||
d79b9b0c DM |
30 | die "internal error ($type ne $sectionId)" if $type ne $sectionId; |
31 | ||
32 | return "section: $type\n"; | |
7e0e6dbe DM |
33 | } |
34 | ||
35 | ||
36 | sub parse_section_header { | |
37 | my ($class, $line) = @_; | |
38 | ||
d79b9b0c DM |
39 | if ($line =~ m/^section:\s*(\S+)\s*$/) { |
40 | my $section = $1; | |
7e0e6dbe | 41 | my $errmsg = undef; # set if you want to skip whole section |
d79b9b0c | 42 | eval { PVE::JSONSchema::pve_verify_configid($section); }; |
7e0e6dbe DM |
43 | $errmsg = $@ if $@; |
44 | my $config = {}; # to return additional attributes | |
d79b9b0c | 45 | return ($section, $section, $errmsg, $config); |
7e0e6dbe DM |
46 | } |
47 | return undef; | |
48 | } | |
49 | ||
ac5d1312 | 50 | package PMG::Config::Admin; |
7e0e6dbe DM |
51 | |
52 | use strict; | |
53 | use warnings; | |
54 | ||
55 | use base qw(PMG::Config::Base); | |
56 | ||
57 | sub type { | |
ac5d1312 | 58 | return 'admin'; |
7e0e6dbe DM |
59 | } |
60 | ||
61 | sub properties { | |
62 | return { | |
63 | dailyreport => { | |
64 | description => "Send daily reports.", | |
65 | type => 'boolean', | |
66 | default => 1, | |
67 | }, | |
f62194b2 DM |
68 | demo => { |
69 | description => "Demo mode - do not start SMTP filter.", | |
70 | type => 'boolean', | |
71 | default => 0, | |
72 | }, | |
73 | email => { | |
74 | description => "Administrator E-Mail address.", | |
75 | type => 'string', format => 'email', | |
76 | default => 'admin@domain.tld', | |
ac5d1312 DM |
77 | }, |
78 | proxyport => { | |
79 | description => "HTTP proxy port.", | |
80 | type => 'integer', | |
81 | minimum => 1, | |
82 | default => 8080, | |
83 | }, | |
84 | proxyserver => { | |
85 | description => "HTTP proxy server address.", | |
86 | type => 'string', | |
87 | }, | |
88 | proxyuser => { | |
89 | description => "HTTP proxy user name.", | |
90 | type => 'string', | |
91 | }, | |
92 | proxypassword => { | |
93 | description => "HTTP proxy password.", | |
94 | type => 'string', | |
95 | }, | |
7e0e6dbe DM |
96 | }; |
97 | } | |
98 | ||
99 | sub options { | |
100 | return { | |
101 | dailyreport => { optional => 1 }, | |
f62194b2 | 102 | demo => { optional => 1 }, |
3d812daf | 103 | email => { optional => 1 }, |
ac5d1312 DM |
104 | proxyport => { optional => 1 }, |
105 | proxyserver => { optional => 1 }, | |
106 | proxyuser => { optional => 1 }, | |
107 | proxypassword => { optional => 1 }, | |
7e0e6dbe DM |
108 | }; |
109 | } | |
110 | ||
111 | package PMG::Config::Spam; | |
112 | ||
113 | use strict; | |
114 | use warnings; | |
115 | ||
116 | use base qw(PMG::Config::Base); | |
117 | ||
118 | sub type { | |
119 | return 'spam'; | |
120 | } | |
121 | ||
122 | sub properties { | |
123 | return { | |
1ccc8e95 DM |
124 | languages => { |
125 | description => "This option is used to specify which languages are considered OK for incoming mail.", | |
126 | type => 'string', | |
127 | pattern => '(all|([a-z][a-z])+( ([a-z][a-z])+)*)', | |
128 | default => 'all', | |
129 | }, | |
130 | use_bayes => { | |
131 | description => "Whether to use the naive-Bayesian-style classifier.", | |
132 | type => 'boolean', | |
133 | default => 1, | |
134 | }, | |
582cfacf DM |
135 | use_awl => { |
136 | description => "Use the Auto-Whitelist plugin.", | |
137 | type => 'boolean', | |
138 | default => 1, | |
139 | }, | |
140 | use_razor => { | |
141 | description => "Whether to use Razor2, if it is available.", | |
142 | type => 'boolean', | |
143 | default => 1, | |
144 | }, | |
03ac6d8f DM |
145 | use_ocr => { |
146 | description => "Enable OCR to scan pictures.", | |
147 | type => 'boolean', | |
148 | default => 0, | |
149 | }, | |
1ccc8e95 DM |
150 | wl_bounce_relays => { |
151 | description => "Whitelist legitimate bounce relays.", | |
152 | type => 'string', | |
153 | }, | |
7e0e6dbe DM |
154 | bounce_score => { |
155 | description => "Additional score for bounce mails.", | |
156 | type => 'integer', | |
157 | minimum => 0, | |
158 | maximum => 1000, | |
159 | default => 0, | |
160 | }, | |
f62194b2 DM |
161 | rbl_checks => { |
162 | description => "Enable real time blacklists (RBL) checks.", | |
163 | type => 'boolean', | |
164 | default => 1, | |
165 | }, | |
166 | maxspamsize => { | |
167 | description => "Maximum size of spam messages in bytes.", | |
168 | type => 'integer', | |
4d76e24e | 169 | minimum => 64, |
f62194b2 DM |
170 | default => 200*1024, |
171 | }, | |
7e0e6dbe DM |
172 | }; |
173 | } | |
174 | ||
175 | sub options { | |
176 | return { | |
582cfacf DM |
177 | use_awl => { optional => 1 }, |
178 | use_razor => { optional => 1 }, | |
03ac6d8f | 179 | use_ocr => { optional => 1 }, |
1ccc8e95 DM |
180 | wl_bounce_relays => { optional => 1 }, |
181 | languages => { optional => 1 }, | |
182 | use_bayes => { optional => 1 }, | |
7e0e6dbe | 183 | bounce_score => { optional => 1 }, |
f62194b2 DM |
184 | rbl_checks => { optional => 1 }, |
185 | maxspamsize => { optional => 1 }, | |
186 | }; | |
187 | } | |
188 | ||
189 | package PMG::Config::ClamAV; | |
190 | ||
191 | use strict; | |
192 | use warnings; | |
193 | ||
194 | use base qw(PMG::Config::Base); | |
195 | ||
196 | sub type { | |
197 | return 'clamav'; | |
198 | } | |
199 | ||
200 | sub properties { | |
201 | return { | |
ac5d1312 DM |
202 | dbmirror => { |
203 | description => "ClamAV database mirror server.", | |
204 | type => 'string', | |
205 | default => 'database.clamav.net', | |
206 | }, | |
207 | archiveblockencrypted => { | |
208 | description => "Wether to block encrypted archives. Mark encrypted archives as viruses.", | |
209 | type => 'boolean', | |
210 | default => 0, | |
211 | }, | |
212 | archivemaxrec => { | |
213 | 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 | 214 | type => 'integer', |
ac5d1312 DM |
215 | minimum => 1, |
216 | default => 5, | |
217 | }, | |
f62194b2 | 218 | archivemaxfiles => { |
ac5d1312 | 219 | 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 |
220 | type => 'integer', |
221 | minimum => 0, | |
222 | default => 1000, | |
223 | }, | |
ac5d1312 DM |
224 | archivemaxsize => { |
225 | description => "Files larger than this limit won't be scanned.", | |
226 | type => 'integer', | |
227 | minimum => 1000000, | |
228 | default => 25000000, | |
229 | }, | |
230 | maxscansize => { | |
231 | description => "Sets the maximum amount of data to be scanned for each input file.", | |
232 | type => 'integer', | |
233 | minimum => 1000000, | |
234 | default => 100000000, | |
235 | }, | |
236 | maxcccount => { | |
237 | description => "This option sets the lowest number of Credit Card or Social Security numbers found in a file to generate a detect.", | |
238 | type => 'integer', | |
239 | minimum => 0, | |
240 | default => 0, | |
241 | }, | |
f62194b2 DM |
242 | }; |
243 | } | |
244 | ||
245 | sub options { | |
246 | return { | |
ac5d1312 DM |
247 | archiveblockencrypted => { optional => 1 }, |
248 | archivemaxrec => { optional => 1 }, | |
f62194b2 | 249 | archivemaxfiles => { optional => 1 }, |
ac5d1312 DM |
250 | archivemaxsize => { optional => 1 }, |
251 | maxscansize => { optional => 1 }, | |
252 | dbmirror => { optional => 1 }, | |
253 | maxcccount => { optional => 1 }, | |
7e0e6dbe DM |
254 | }; |
255 | } | |
256 | ||
d9dc3c08 DM |
257 | package PMG::Config::Mail; |
258 | ||
259 | use strict; | |
260 | use warnings; | |
261 | ||
f62194b2 DM |
262 | use PVE::ProcFSTools; |
263 | ||
d9dc3c08 DM |
264 | use base qw(PMG::Config::Base); |
265 | ||
266 | sub type { | |
267 | return 'mail'; | |
268 | } | |
269 | ||
f62194b2 DM |
270 | my $physicalmem = 0; |
271 | sub physical_memory { | |
272 | ||
273 | return $physicalmem if $physicalmem; | |
274 | ||
275 | my $info = PVE::ProcFSTools::read_meminfo(); | |
276 | my $total = int($info->{memtotal} / (1024*1024)); | |
277 | ||
278 | return $total; | |
279 | } | |
280 | ||
281 | sub get_max_filters { | |
282 | # estimate optimal number of filter servers | |
283 | ||
284 | my $max_servers = 5; | |
285 | my $servermem = 120; | |
286 | my $memory = physical_memory(); | |
287 | my $add_servers = int(($memory - 512)/$servermem); | |
288 | $max_servers += $add_servers if $add_servers > 0; | |
289 | $max_servers = 40 if $max_servers > 40; | |
290 | ||
291 | return $max_servers - 2; | |
292 | } | |
293 | ||
f609bf7f DM |
294 | sub get_max_smtpd { |
295 | # estimate optimal number of smtpd daemons | |
296 | ||
297 | my $max_servers = 25; | |
298 | my $servermem = 20; | |
299 | my $memory = physical_memory(); | |
300 | my $add_servers = int(($memory - 512)/$servermem); | |
301 | $max_servers += $add_servers if $add_servers > 0; | |
302 | $max_servers = 100 if $max_servers > 100; | |
303 | return $max_servers; | |
304 | } | |
305 | ||
03907162 DM |
306 | sub get_max_policy { |
307 | # estimate optimal number of proxpolicy servers | |
308 | my $max_servers = 2; | |
309 | my $memory = physical_memory(); | |
310 | $max_servers = 5 if $memory >= 500; | |
311 | return $max_servers; | |
312 | } | |
f609bf7f | 313 | |
d9dc3c08 DM |
314 | sub properties { |
315 | return { | |
75a20f14 DM |
316 | int_port => { |
317 | description => "SMTP port number for outgoing mail (trusted).", | |
318 | type => 'integer', | |
319 | minimum => 1, | |
320 | maximum => 65535, | |
321 | default => 25, | |
322 | }, | |
323 | ext_port => { | |
7b19cc5c | 324 | description => "SMTP port number for incoming mail (untrusted). This must be a different number than 'int_port'.", |
75a20f14 DM |
325 | type => 'integer', |
326 | minimum => 1, | |
327 | maximum => 65535, | |
328 | default => 26, | |
329 | }, | |
f609bf7f DM |
330 | relay => { |
331 | description => "The default mail delivery transport (incoming mails).", | |
66af5153 | 332 | type => 'string', format => 'address', |
f609bf7f DM |
333 | }, |
334 | relayport => { | |
335 | description => "SMTP port number for relay host.", | |
336 | type => 'integer', | |
337 | minimum => 1, | |
338 | maximum => 65535, | |
339 | default => 25, | |
340 | }, | |
341 | relaynomx => { | |
342 | description => "Disable MX lookups for default relay.", | |
343 | type => 'boolean', | |
344 | default => 0, | |
345 | }, | |
346 | smarthost => { | |
347 | description => "When set, all outgoing mails are deliverd to the specified smarthost.", | |
3bb296d4 | 348 | type => 'string', format => 'address', |
f609bf7f | 349 | }, |
d9dc3c08 DM |
350 | banner => { |
351 | description => "ESMTP banner.", | |
352 | type => 'string', | |
353 | maxLength => 1024, | |
354 | default => 'ESMTP Proxmox', | |
355 | }, | |
f62194b2 | 356 | max_filters => { |
03907162 | 357 | description => "Maximum number of pmg-smtp-filter processes.", |
f62194b2 DM |
358 | type => 'integer', |
359 | minimum => 3, | |
360 | maximum => 40, | |
361 | default => get_max_filters(), | |
362 | }, | |
03907162 DM |
363 | max_policy => { |
364 | description => "Maximum number of pmgpolicy processes.", | |
365 | type => 'integer', | |
366 | minimum => 2, | |
367 | maximum => 10, | |
368 | default => get_max_policy(), | |
369 | }, | |
f609bf7f DM |
370 | max_smtpd_in => { |
371 | description => "Maximum number of SMTP daemon processes (in).", | |
372 | type => 'integer', | |
373 | minimum => 3, | |
374 | maximum => 100, | |
375 | default => get_max_smtpd(), | |
376 | }, | |
377 | max_smtpd_out => { | |
378 | description => "Maximum number of SMTP daemon processes (out).", | |
379 | type => 'integer', | |
380 | minimum => 3, | |
381 | maximum => 100, | |
382 | default => get_max_smtpd(), | |
383 | }, | |
384 | conn_count_limit => { | |
385 | description => "How many simultaneous connections any client is allowed to make to this service. To disable this feature, specify a limit of 0.", | |
386 | type => 'integer', | |
387 | minimum => 0, | |
388 | default => 50, | |
389 | }, | |
390 | conn_rate_limit => { | |
391 | 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.", | |
392 | type => 'integer', | |
393 | minimum => 0, | |
394 | default => 0, | |
395 | }, | |
396 | message_rate_limit => { | |
397 | 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.", | |
398 | type => 'integer', | |
399 | minimum => 0, | |
400 | default => 0, | |
401 | }, | |
f62194b2 DM |
402 | hide_received => { |
403 | description => "Hide received header in outgoing mails.", | |
404 | type => 'boolean', | |
ac5d1312 DM |
405 | default => 0, |
406 | }, | |
f609bf7f | 407 | maxsize => { |
ac5d1312 DM |
408 | description => "Maximum email size. Larger mails are rejected.", |
409 | type => 'integer', | |
410 | minimum => 1024, | |
411 | default => 1024*1024*10, | |
f62194b2 | 412 | }, |
f609bf7f DM |
413 | dwarning => { |
414 | description => "SMTP delay warning time (in hours).", | |
415 | type => 'integer', | |
416 | minimum => 0, | |
417 | default => 4, | |
418 | }, | |
419 | use_rbl => { | |
4d76e24e | 420 | description => "Use Realtime Blacklists.", |
f609bf7f DM |
421 | type => 'boolean', |
422 | default => 1, | |
423 | }, | |
424 | tls => { | |
589be6da DM |
425 | description => "Enable TLS.", |
426 | type => 'boolean', | |
427 | default => 0, | |
428 | }, | |
429 | tlslog => { | |
430 | description => "Enable TLS Logging.", | |
431 | type => 'boolean', | |
432 | default => 0, | |
433 | }, | |
434 | tlsheader => { | |
435 | description => "Add TLS received header.", | |
f609bf7f DM |
436 | type => 'boolean', |
437 | default => 0, | |
438 | }, | |
439 | spf => { | |
4d76e24e | 440 | description => "Use Sender Policy Framework.", |
f609bf7f DM |
441 | type => 'boolean', |
442 | default => 1, | |
443 | }, | |
444 | greylist => { | |
4d76e24e | 445 | description => "Use Greylisting.", |
f609bf7f DM |
446 | type => 'boolean', |
447 | default => 1, | |
448 | }, | |
449 | helotests => { | |
4d76e24e | 450 | description => "Use SMTP HELO tests.", |
f609bf7f DM |
451 | type => 'boolean', |
452 | default => 0, | |
453 | }, | |
454 | rejectunknown => { | |
4d76e24e | 455 | description => "Reject unknown clients.", |
f609bf7f DM |
456 | type => 'boolean', |
457 | default => 0, | |
458 | }, | |
459 | rejectunknownsender => { | |
4d76e24e | 460 | description => "Reject unknown senders.", |
f609bf7f DM |
461 | type => 'boolean', |
462 | default => 0, | |
463 | }, | |
464 | verifyreceivers => { | |
3791e936 | 465 | description => "Enable receiver verification. The value spefifies the numerical reply code when the Postfix SMTP server rejects a recipient address.", |
90822f27 DM |
466 | type => 'string', |
467 | enum => ['450', '550'], | |
f609bf7f DM |
468 | }, |
469 | dnsbl_sites => { | |
470 | description => "Optional list of DNS white/blacklist domains (see postscreen_dnsbl_sites parameter).", | |
471 | type => 'string', | |
472 | }, | |
d9dc3c08 DM |
473 | }; |
474 | } | |
475 | ||
476 | sub options { | |
477 | return { | |
75a20f14 DM |
478 | int_port => { optional => 1 }, |
479 | ext_port => { optional => 1 }, | |
3d9837d9 | 480 | smarthost => { optional => 1 }, |
f609bf7f DM |
481 | relay => { optional => 1 }, |
482 | relayport => { optional => 1 }, | |
483 | relaynomx => { optional => 1 }, | |
484 | dwarning => { optional => 1 }, | |
485 | max_smtpd_in => { optional => 1 }, | |
486 | max_smtpd_out => { optional => 1 }, | |
487 | greylist => { optional => 1 }, | |
488 | helotests => { optional => 1 }, | |
489 | use_rbl => { optional => 1 }, | |
490 | tls => { optional => 1 }, | |
589be6da DM |
491 | tlslog => { optional => 1 }, |
492 | tlsheader => { optional => 1 }, | |
f609bf7f DM |
493 | spf => { optional => 1 }, |
494 | maxsize => { optional => 1 }, | |
d9dc3c08 | 495 | banner => { optional => 1 }, |
f62194b2 | 496 | max_filters => { optional => 1 }, |
03907162 | 497 | max_policy => { optional => 1 }, |
f62194b2 | 498 | hide_received => { optional => 1 }, |
f609bf7f DM |
499 | rejectunknown => { optional => 1 }, |
500 | rejectunknownsender => { optional => 1 }, | |
501 | conn_count_limit => { optional => 1 }, | |
502 | conn_rate_limit => { optional => 1 }, | |
503 | message_rate_limit => { optional => 1 }, | |
504 | verifyreceivers => { optional => 1 }, | |
505 | dnsbl_sites => { optional => 1 }, | |
d9dc3c08 DM |
506 | }; |
507 | } | |
7e0e6dbe DM |
508 | package PMG::Config; |
509 | ||
510 | use strict; | |
511 | use warnings; | |
9123cab5 | 512 | use IO::File; |
7e0e6dbe | 513 | use Data::Dumper; |
4ccdc564 | 514 | use Template; |
7e0e6dbe | 515 | |
9123cab5 | 516 | use PVE::SafeSyslog; |
ba323310 | 517 | use PVE::Tools qw($IPV4RE $IPV6RE); |
7e0e6dbe | 518 | use PVE::INotify; |
b86ac4eb | 519 | use PVE::JSONSchema; |
7e0e6dbe | 520 | |
ac5d1312 | 521 | PMG::Config::Admin->register(); |
d9dc3c08 | 522 | PMG::Config::Mail->register(); |
7e0e6dbe | 523 | PMG::Config::Spam->register(); |
f62194b2 | 524 | PMG::Config::ClamAV->register(); |
7e0e6dbe DM |
525 | |
526 | # initialize all plugins | |
527 | PMG::Config::Base->init(); | |
528 | ||
b86ac4eb DM |
529 | PVE::JSONSchema::register_format( |
530 | 'transport-domain', \&pmg_verify_transport_domain); | |
531 | sub pmg_verify_transport_domain { | |
532 | my ($name, $noerr) = @_; | |
533 | ||
534 | # like dns-name, but can contain leading dot | |
535 | my $namere = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)"; | |
536 | ||
537 | if ($name !~ /^\.?(${namere}\.)*${namere}$/) { | |
538 | return undef if $noerr; | |
539 | die "value does not look like a valid transport domain\n"; | |
540 | } | |
541 | return $name; | |
542 | } | |
f62194b2 DM |
543 | |
544 | sub new { | |
545 | my ($type) = @_; | |
546 | ||
547 | my $class = ref($type) || $type; | |
548 | ||
549 | my $cfg = PVE::INotify::read_file("pmg.conf"); | |
550 | ||
551 | return bless $cfg, $class; | |
552 | } | |
553 | ||
be6e2db9 DM |
554 | sub write { |
555 | my ($self) = @_; | |
556 | ||
557 | PVE::INotify::write_file("pmg.conf", $self); | |
558 | } | |
559 | ||
f21d933c DM |
560 | my $lockfile = "/var/lock/pmgconfig.lck"; |
561 | ||
562 | sub lock_config { | |
563 | my ($code, $errmsg) = @_; | |
564 | ||
565 | my $p = PVE::Tools::lock_file($lockfile, undef, $code); | |
566 | if (my $err = $@) { | |
567 | $errmsg ? die "$errmsg: $err" : die $err; | |
568 | } | |
569 | } | |
570 | ||
062f0498 | 571 | # set section values |
062f0498 DM |
572 | sub set { |
573 | my ($self, $section, $key, $value) = @_; | |
574 | ||
575 | my $pdata = PMG::Config::Base->private(); | |
576 | ||
062f0498 DM |
577 | my $plugin = $pdata->{plugins}->{$section}; |
578 | die "no such section '$section'" if !$plugin; | |
579 | ||
062f0498 DM |
580 | if (defined($value)) { |
581 | my $tmp = PMG::Config::Base->check_value($section, $key, $value, $section, 0); | |
d79b9b0c DM |
582 | $self->{ids}->{$section} = { type => $section } if !defined($self->{ids}->{$section}); |
583 | $self->{ids}->{$section}->{$key} = PMG::Config::Base->decode_value($section, $key, $tmp); | |
062f0498 | 584 | } else { |
d79b9b0c DM |
585 | if (defined($self->{ids}->{$section})) { |
586 | delete $self->{ids}->{$section}->{$key}; | |
062f0498 DM |
587 | } |
588 | } | |
589 | ||
590 | return undef; | |
591 | } | |
592 | ||
f62194b2 | 593 | # get section value or default |
f62194b2 DM |
594 | sub get { |
595 | my ($self, $section, $key) = @_; | |
596 | ||
597 | my $pdata = PMG::Config::Base->private(); | |
f62194b2 | 598 | my $pdesc = $pdata->{propertyList}->{$key}; |
3d9837d9 DM |
599 | die "no such property '$section/$key'\n" |
600 | if !(defined($pdesc) && defined($pdata->{options}->{$section}) && | |
601 | defined($pdata->{options}->{$section}->{$key})); | |
f62194b2 | 602 | |
d79b9b0c DM |
603 | if (defined($self->{ids}->{$section}) && |
604 | defined(my $value = $self->{ids}->{$section}->{$key})) { | |
f62194b2 | 605 | return $value; |
1ccc8e95 | 606 | } |
f62194b2 DM |
607 | |
608 | return $pdesc->{default}; | |
609 | } | |
610 | ||
1ccc8e95 | 611 | # get a whole section with default value |
1ccc8e95 DM |
612 | sub get_section { |
613 | my ($self, $section) = @_; | |
614 | ||
615 | my $pdata = PMG::Config::Base->private(); | |
616 | return undef if !defined($pdata->{options}->{$section}); | |
617 | ||
618 | my $res = {}; | |
619 | ||
620 | foreach my $key (keys %{$pdata->{options}->{$section}}) { | |
621 | ||
622 | my $pdesc = $pdata->{propertyList}->{$key}; | |
623 | ||
d79b9b0c DM |
624 | if (defined($self->{ids}->{$section}) && |
625 | defined(my $value = $self->{ids}->{$section}->{$key})) { | |
1ccc8e95 DM |
626 | $res->{$key} = $value; |
627 | next; | |
628 | } | |
629 | $res->{$key} = $pdesc->{default}; | |
630 | } | |
631 | ||
632 | return $res; | |
633 | } | |
634 | ||
be16be07 | 635 | # get a whole config with default values |
be16be07 DM |
636 | sub get_config { |
637 | my ($self) = @_; | |
638 | ||
9dab5fe5 DM |
639 | my $pdata = PMG::Config::Base->private(); |
640 | ||
be16be07 DM |
641 | my $res = {}; |
642 | ||
9dab5fe5 | 643 | foreach my $type (keys %{$pdata->{plugins}}) { |
9dab5fe5 DM |
644 | my $plugin = $pdata->{plugins}->{$type}; |
645 | $res->{$type} = $self->get_section($type); | |
be16be07 DM |
646 | } |
647 | ||
648 | return $res; | |
649 | } | |
650 | ||
7e0e6dbe DM |
651 | sub read_pmg_conf { |
652 | my ($filename, $fh) = @_; | |
f62194b2 | 653 | |
7e0e6dbe | 654 | local $/ = undef; # slurp mode |
f62194b2 | 655 | |
9dfe7c16 | 656 | my $raw = <$fh> if defined($fh); |
7e0e6dbe DM |
657 | |
658 | return PMG::Config::Base->parse_config($filename, $raw); | |
659 | } | |
660 | ||
661 | sub write_pmg_conf { | |
662 | my ($filename, $fh, $cfg) = @_; | |
663 | ||
664 | my $raw = PMG::Config::Base->write_config($filename, $cfg); | |
665 | ||
666 | PVE::Tools::safe_print($filename, $fh, $raw); | |
667 | } | |
668 | ||
3278b571 | 669 | PVE::INotify::register_file('pmg.conf', "/etc/pmg/pmg.conf", |
f62194b2 | 670 | \&read_pmg_conf, |
9dfe7c16 DM |
671 | \&write_pmg_conf, |
672 | undef, always_call_parser => 1); | |
7e0e6dbe | 673 | |
f609bf7f DM |
674 | # parsers/writers for other files |
675 | ||
3278b571 | 676 | my $domainsfilename = "/etc/pmg/domains"; |
f609bf7f | 677 | |
c3f4336c DM |
678 | sub postmap_pmg_domains { |
679 | PMG::Utils::run_postmap($domainsfilename); | |
680 | } | |
681 | ||
f609bf7f DM |
682 | sub read_pmg_domains { |
683 | my ($filename, $fh) = @_; | |
684 | ||
b7298186 | 685 | my $domains = {}; |
f609bf7f | 686 | |
b7298186 | 687 | my $comment = ''; |
f609bf7f DM |
688 | if (defined($fh)) { |
689 | while (defined(my $line = <$fh>)) { | |
3118b703 DM |
690 | chomp $line; |
691 | next if $line =~ m/^\s*$/; | |
b7298186 DM |
692 | if ($line =~ m/^#(.*)\s*$/) { |
693 | $comment = $1; | |
694 | next; | |
695 | } | |
696 | if ($line =~ m/^(\S+)\s.*$/) { | |
f609bf7f | 697 | my $domain = $1; |
b7298186 DM |
698 | $domains->{$domain} = { |
699 | domain => $domain, comment => $comment }; | |
700 | $comment = ''; | |
3118b703 DM |
701 | } else { |
702 | warn "parse error in '$filename': $line\n"; | |
703 | $comment = ''; | |
f609bf7f DM |
704 | } |
705 | } | |
706 | } | |
707 | ||
708 | return $domains; | |
709 | } | |
710 | ||
711 | sub write_pmg_domains { | |
b7298186 DM |
712 | my ($filename, $fh, $domains) = @_; |
713 | ||
714 | foreach my $domain (sort keys %$domains) { | |
715 | my $comment = $domains->{$domain}->{comment}; | |
716 | PVE::Tools::safe_print($filename, $fh, "#$comment\n") | |
717 | if defined($comment) && $comment !~ m/^\s*$/; | |
f609bf7f | 718 | |
6b31da64 | 719 | PVE::Tools::safe_print($filename, $fh, "$domain 1\n"); |
f609bf7f DM |
720 | } |
721 | } | |
722 | ||
723 | PVE::INotify::register_file('domains', $domainsfilename, | |
724 | \&read_pmg_domains, | |
725 | \&write_pmg_domains, | |
726 | undef, always_call_parser => 1); | |
727 | ||
bef31f06 DM |
728 | my $mynetworks_filename = "/etc/pmg/mynetworks"; |
729 | ||
730 | sub postmap_pmg_mynetworks { | |
731 | PMG::Utils::run_postmap($mynetworks_filename); | |
732 | } | |
733 | ||
734 | sub read_pmg_mynetworks { | |
735 | my ($filename, $fh) = @_; | |
736 | ||
737 | my $mynetworks = {}; | |
738 | ||
739 | my $comment = ''; | |
740 | if (defined($fh)) { | |
741 | while (defined(my $line = <$fh>)) { | |
742 | chomp $line; | |
743 | next if $line =~ m/^\s*$/; | |
744 | if ($line =~ m!^((?:$IPV4RE|$IPV6RE))/(\d+)\s*(?:#(.*)\s*)?$!) { | |
745 | my ($network, $prefix_size, $comment) = ($1, $2, $3); | |
746 | my $cidr = "$network/${prefix_size}"; | |
747 | $mynetworks->{$cidr} = { | |
748 | cidr => $cidr, | |
749 | network_address => $network, | |
750 | prefix_size => $prefix_size, | |
751 | comment => $comment // '', | |
752 | }; | |
753 | } else { | |
754 | warn "parse error in '$filename': $line\n"; | |
755 | } | |
756 | } | |
757 | } | |
758 | ||
759 | return $mynetworks; | |
760 | } | |
761 | ||
762 | sub write_pmg_mynetworks { | |
763 | my ($filename, $fh, $mynetworks) = @_; | |
764 | ||
765 | foreach my $cidr (sort keys %$mynetworks) { | |
766 | my $data = $mynetworks->{$cidr}; | |
767 | my $comment = $data->{comment} // '*'; | |
768 | PVE::Tools::safe_print($filename, $fh, "$cidr #$comment\n"); | |
769 | } | |
770 | } | |
771 | ||
772 | PVE::INotify::register_file('mynetworks', $mynetworks_filename, | |
773 | \&read_pmg_mynetworks, | |
774 | \&write_pmg_mynetworks, | |
775 | undef, always_call_parser => 1); | |
776 | ||
cd533938 | 777 | my $transport_map_filename = "/etc/pmg/transport"; |
3546daf0 | 778 | |
3118b703 DM |
779 | sub postmap_pmg_transport { |
780 | PMG::Utils::run_postmap($transport_map_filename); | |
781 | } | |
782 | ||
3546daf0 DM |
783 | sub read_transport_map { |
784 | my ($filename, $fh) = @_; | |
785 | ||
786 | return [] if !defined($fh); | |
787 | ||
788 | my $res = {}; | |
789 | ||
3118b703 | 790 | my $comment = ''; |
b7c49fec | 791 | |
3546daf0 DM |
792 | while (defined(my $line = <$fh>)) { |
793 | chomp $line; | |
794 | next if $line =~ m/^\s*$/; | |
3118b703 DM |
795 | if ($line =~ m/^#(.*)\s*$/) { |
796 | $comment = $1; | |
797 | next; | |
798 | } | |
3546daf0 | 799 | |
b7c49fec DM |
800 | my $parse_error = sub { |
801 | my ($err) = @_; | |
802 | warn "parse error in '$filename': $line - $err"; | |
803 | $comment = ''; | |
804 | }; | |
805 | ||
ba323310 | 806 | if ($line =~ m/^(\S+)\s+smtp:(\S+):(\d+)\s*$/) { |
3118b703 | 807 | my ($domain, $host, $port) = ($1, $2, $3); |
3546daf0 | 808 | |
b7c49fec DM |
809 | eval { pmg_verify_transport_domain($domain); }; |
810 | if (my $err = $@) { | |
811 | $parse_error->($err); | |
812 | next; | |
813 | } | |
53904163 | 814 | my $use_mx = 1; |
3546daf0 DM |
815 | if ($host =~ m/^\[(.*)\]$/) { |
816 | $host = $1; | |
53904163 | 817 | $use_mx = 0; |
3546daf0 DM |
818 | } |
819 | ||
b7c49fec DM |
820 | eval { PVE::JSONSchema::pve_verify_address($host); }; |
821 | if (my $err = $@) { | |
822 | $parse_error->($err); | |
823 | next; | |
824 | } | |
825 | ||
3118b703 DM |
826 | my $data = { |
827 | domain => $domain, | |
828 | host => $host, | |
829 | port => $port, | |
53904163 | 830 | use_mx => $use_mx, |
3118b703 DM |
831 | comment => $comment, |
832 | }; | |
833 | $res->{$domain} = $data; | |
834 | $comment = ''; | |
835 | } else { | |
b7c49fec | 836 | $parse_error->('wrong format'); |
3546daf0 DM |
837 | } |
838 | } | |
839 | ||
3118b703 | 840 | return $res; |
3546daf0 DM |
841 | } |
842 | ||
cd533938 | 843 | sub write_transport_map { |
3546daf0 DM |
844 | my ($filename, $fh, $tmap) = @_; |
845 | ||
846 | return if !$tmap; | |
847 | ||
3118b703 DM |
848 | foreach my $domain (sort keys %$tmap) { |
849 | my $data = $tmap->{$domain}; | |
3546daf0 | 850 | |
3118b703 DM |
851 | my $comment = $data->{comment}; |
852 | PVE::Tools::safe_print($filename, $fh, "#$comment\n") | |
853 | if defined($comment) && $comment !~ m/^\s*$/; | |
854 | ||
ba323310 DM |
855 | my $use_mx = $data->{use_mx}; |
856 | $use_mx = 0 if $data->{host} =~ m/^(?:$IPV4RE|$IPV6RE)$/; | |
857 | ||
858 | if ($use_mx) { | |
3118b703 | 859 | PVE::Tools::safe_print( |
53904163 | 860 | $filename, $fh, "$data->{domain} smtp:$data->{host}:$data->{port}\n"); |
3118b703 DM |
861 | } else { |
862 | PVE::Tools::safe_print( | |
53904163 | 863 | $filename, $fh, "$data->{domain} smtp:[$data->{host}]:$data->{port}\n"); |
3546daf0 DM |
864 | } |
865 | } | |
866 | } | |
867 | ||
868 | PVE::INotify::register_file('transport', $transport_map_filename, | |
869 | \&read_transport_map, | |
cd533938 | 870 | \&write_transport_map, |
3546daf0 | 871 | undef, always_call_parser => 1); |
7e0e6dbe | 872 | |
4ccdc564 DM |
873 | # config file generation using templates |
874 | ||
07b3face DM |
875 | sub get_template_vars { |
876 | my ($self) = @_; | |
4ccdc564 DM |
877 | |
878 | my $vars = { pmg => $self->get_config() }; | |
879 | ||
f609bf7f DM |
880 | my $nodename = PVE::INotify::nodename(); |
881 | my $int_ip = PMG::Cluster::remote_node_ip($nodename); | |
882 | my $int_net_cidr = PMG::Utils::find_local_network_for_ip($int_ip); | |
f609bf7f DM |
883 | $vars->{ipconfig}->{int_ip} = $int_ip; |
884 | # $vars->{ipconfig}->{int_net_cidr} = $int_net_cidr; | |
f609bf7f | 885 | |
ba323310 DM |
886 | my $transportnets = []; |
887 | ||
888 | my $tmap = PVE::INotify::read_file('transport'); | |
889 | foreach my $domain (sort keys %$tmap) { | |
890 | my $data = $tmap->{$domain}; | |
891 | my $host = $data->{host}; | |
892 | if ($host =~ m/^$IPV4RE$/) { | |
893 | push @$transportnets, "$host/32"; | |
894 | } elsif ($host =~ m/^$IPV6RE$/) { | |
895 | push @$transportnets, "[$host]/128"; | |
896 | } | |
897 | } | |
898 | ||
f609bf7f DM |
899 | $vars->{postfix}->{transportnets} = join(' ', @$transportnets); |
900 | ||
901 | my $mynetworks = [ '127.0.0.0/8', '[::1]/128' ]; | |
902 | push @$mynetworks, @$transportnets; | |
903 | push @$mynetworks, $int_net_cidr; | |
bef31f06 | 904 | push @$mynetworks, 'hash:/etc/pmg/mynetworks'; |
f609bf7f | 905 | |
bef31f06 | 906 | my $netlist = PVE::INotify::read_file('mynetworks'); |
f609bf7f DM |
907 | # add default relay to mynetworks |
908 | if (my $relay = $self->get('mail', 'relay')) { | |
ba323310 | 909 | if ($relay =~ m/^$IPV4RE$/) { |
f609bf7f | 910 | push @$mynetworks, "$relay/32"; |
ba323310 | 911 | } elsif ($relay =~ m/^$IPV6RE$/) { |
f609bf7f DM |
912 | push @$mynetworks, "[$relay]/128"; |
913 | } else { | |
66af5153 | 914 | # DNS name - do nothing ? |
f609bf7f DM |
915 | } |
916 | } | |
917 | ||
918 | $vars->{postfix}->{mynetworks} = join(' ', @$mynetworks); | |
919 | ||
920 | my $usepolicy = 0; | |
921 | $usepolicy = 1 if $self->get('mail', 'greylist') || | |
922 | $self->get('mail', 'spf') || $self->get('mail', 'use_rbl'); | |
923 | $vars->{postfix}->{usepolicy} = $usepolicy; | |
924 | ||
925 | my $resolv = PVE::INotify::read_file('resolvconf'); | |
926 | $vars->{dns}->{hostname} = $nodename; | |
927 | $vars->{dns}->{domain} = $resolv->{search}; | |
928 | ||
07b3face DM |
929 | return $vars; |
930 | } | |
931 | ||
932 | # rewrite file from template | |
933 | # return true if file has changed | |
934 | sub rewrite_config_file { | |
935 | my ($self, $tmplname, $dstfn) = @_; | |
936 | ||
937 | my $demo = $self->get('admin', 'demo'); | |
938 | ||
939 | my $srcfn = ($tmplname =~ m|^.?/|) ? | |
940 | $tmplname : "/var/lib/pmg/templates/$tmplname"; | |
941 | ||
942 | if ($demo) { | |
943 | my $demosrc = "$srcfn.demo"; | |
944 | $srcfn = $demosrc if -f $demosrc; | |
945 | } | |
946 | ||
c248d69f | 947 | my ($perm, $uid, $gid); |
07b3face DM |
948 | |
949 | my $srcfd = IO::File->new ($srcfn, "r") | |
950 | || die "cant read template '$srcfn' - $!: ERROR"; | |
951 | ||
952 | if ($dstfn eq '/etc/fetchmailrc') { | |
953 | (undef, undef, $uid, $gid) = getpwnam('fetchmail'); | |
954 | $perm = 0600; | |
955 | } elsif ($dstfn eq '/etc/clamav/freshclam.conf') { | |
956 | # needed if file contains a HTTPProxyPasswort | |
957 | ||
958 | $uid = getpwnam('clamav'); | |
959 | $gid = getgrnam('adm'); | |
960 | $perm = 0600; | |
961 | } | |
962 | ||
963 | my $template = Template->new({}); | |
964 | ||
965 | my $vars = $self->get_template_vars(); | |
966 | ||
c248d69f | 967 | my $output = ''; |
07b3face DM |
968 | |
969 | $template->process($srcfd, $vars, \$output) || | |
4ccdc564 DM |
970 | die $template->error(); |
971 | ||
972 | $srcfd->close(); | |
07b3face DM |
973 | |
974 | my $old = PVE::Tools::file_get_contents($dstfn, 128*1024) if -f $dstfn; | |
975 | ||
976 | return 0 if defined($old) && ($old eq $output); # no change | |
977 | ||
978 | PVE::Tools::file_set_contents($dstfn, $output, $perm); | |
979 | ||
980 | if (defined($uid) && defined($gid)) { | |
981 | chown($uid, $gid, $dstfn); | |
982 | } | |
983 | ||
984 | return 1; | |
4ccdc564 DM |
985 | } |
986 | ||
9123cab5 DM |
987 | # rewrite spam configuration |
988 | sub rewrite_config_spam { | |
989 | my ($self) = @_; | |
990 | ||
991 | my $use_awl = $self->get('spam', 'use_awl'); | |
992 | my $use_bayes = $self->get('spam', 'use_bayes'); | |
993 | my $use_razor = $self->get('spam', 'use_razor'); | |
994 | ||
17424665 DM |
995 | my $changes = 0; |
996 | ||
9123cab5 | 997 | # delete AW and bayes databases if those features are disabled |
17424665 DM |
998 | if (!$use_awl) { |
999 | $changes = 1 if unlink '/root/.spamassassin/auto-whitelist'; | |
1000 | } | |
1001 | ||
9123cab5 | 1002 | if (!$use_bayes) { |
17424665 DM |
1003 | $changes = 1 if unlink '/root/.spamassassin/bayes_journal'; |
1004 | $changes = 1 if unlink '/root/.spamassassin/bayes_seen'; | |
1005 | $changes = 1 if unlink '/root/.spamassassin/bayes_toks'; | |
9123cab5 DM |
1006 | } |
1007 | ||
1008 | # make sure we have a custom.cf file (else cluster sync fails) | |
1009 | IO::File->new('/etc/mail/spamassassin/custom.cf', 'a', 0644); | |
1010 | ||
17424665 DM |
1011 | $changes = 1 if $self->rewrite_config_file( |
1012 | 'local.cf.in', '/etc/mail/spamassassin/local.cf'); | |
1013 | ||
1014 | $changes = 1 if $self->rewrite_config_file( | |
1015 | 'init.pre.in', '/etc/mail/spamassassin/init.pre'); | |
1016 | ||
1017 | $changes = 1 if $self->rewrite_config_file( | |
1018 | 'v310.pre.in', '/etc/mail/spamassassin/v310.pre'); | |
1019 | ||
1020 | $changes = 1 if $self->rewrite_config_file( | |
1021 | 'v320.pre.in', '/etc/mail/spamassassin/v320.pre'); | |
9123cab5 DM |
1022 | |
1023 | if ($use_razor) { | |
1024 | mkdir "/root/.razor"; | |
17424665 DM |
1025 | |
1026 | $changes = 1 if $self->rewrite_config_file( | |
1027 | 'razor-agent.conf.in', '/root/.razor/razor-agent.conf'); | |
1028 | ||
9123cab5 DM |
1029 | if (! -e '/root/.razor/identity') { |
1030 | eval { | |
1031 | my $timeout = 30; | |
17424665 DM |
1032 | PVE::Tools::run_command(['razor-admin', '-discover'], timeout => $timeout); |
1033 | PVE::Tools::run_command(['razor-admin', '-register'], timeout => $timeout); | |
9123cab5 DM |
1034 | }; |
1035 | my $err = $@; | |
1036 | syslog('info', msgquote ("registering razor failed: $err")) if $err; | |
1037 | } | |
1038 | } | |
17424665 DM |
1039 | |
1040 | return $changes; | |
9123cab5 DM |
1041 | } |
1042 | ||
ac5d1312 DM |
1043 | # rewrite ClamAV configuration |
1044 | sub rewrite_config_clam { | |
1045 | my ($self) = @_; | |
1046 | ||
17424665 DM |
1047 | return $self->rewrite_config_file( |
1048 | 'clamd.conf.in', '/etc/clamav/clamd.conf'); | |
1049 | } | |
1050 | ||
1051 | sub rewrite_config_freshclam { | |
1052 | my ($self) = @_; | |
1053 | ||
1054 | return $self->rewrite_config_file( | |
1055 | 'freshclam.conf.in', '/etc/clamav/freshclam.conf'); | |
ac5d1312 DM |
1056 | } |
1057 | ||
86737f12 DM |
1058 | sub rewrite_config_postgres { |
1059 | my ($self) = @_; | |
1060 | ||
1061 | my $pgconfdir = "/etc/postgresql/9.6/main"; | |
1062 | ||
17424665 DM |
1063 | my $changes = 0; |
1064 | ||
1065 | $changes = 1 if $self->rewrite_config_file( | |
1066 | 'pg_hba.conf.in', "$pgconfdir/pg_hba.conf"); | |
1067 | ||
1068 | $changes = 1 if $self->rewrite_config_file( | |
1069 | 'postgresql.conf.in', "$pgconfdir/postgresql.conf"); | |
1070 | ||
1071 | return $changes; | |
86737f12 DM |
1072 | } |
1073 | ||
1074 | # rewrite /root/.forward | |
1075 | sub rewrite_dot_forward { | |
1076 | my ($self) = @_; | |
1077 | ||
c248d69f | 1078 | my $dstfn = '/root/.forward'; |
86737f12 | 1079 | |
0bb9a01a | 1080 | my $email = $self->get('admin', 'email'); |
c248d69f | 1081 | |
e14fda7a | 1082 | my $output = ''; |
86737f12 | 1083 | if ($email && $email =~ m/\s*(\S+)\s*/) { |
c248d69f | 1084 | $output = "$1\n"; |
86737f12 DM |
1085 | } else { |
1086 | # empty .forward does not forward mails (see man local) | |
1087 | } | |
17424665 | 1088 | |
c248d69f DM |
1089 | my $old = PVE::Tools::file_get_contents($dstfn, 128*1024) if -f $dstfn; |
1090 | ||
1091 | return 0 if defined($old) && ($old eq $output); # no change | |
1092 | ||
1093 | PVE::Tools::file_set_contents($dstfn, $output); | |
1094 | ||
1095 | return 1; | |
86737f12 DM |
1096 | } |
1097 | ||
f609bf7f DM |
1098 | # rewrite /etc/postfix/* |
1099 | sub rewrite_config_postfix { | |
1100 | my ($self) = @_; | |
1101 | ||
3546daf0 | 1102 | # make sure we have required files (else postfix start fails) |
b7298186 | 1103 | postmap_pmg_domains(); |
ba323310 | 1104 | postmap_pmg_transport(); |
bef31f06 | 1105 | postmap_pmg_mynetworks(); |
b7298186 | 1106 | |
3546daf0 | 1107 | IO::File->new($transport_map_filename, 'a', 0644); |
f609bf7f | 1108 | |
17424665 DM |
1109 | my $changes = 0; |
1110 | ||
f609bf7f DM |
1111 | if ($self->get('mail', 'tls')) { |
1112 | eval { | |
bc44eb02 | 1113 | PMG::Utils::gen_proxmox_tls_cert(); |
f609bf7f DM |
1114 | }; |
1115 | syslog ('info', msgquote ("generating certificate failed: $@")) if $@; | |
1116 | } | |
1117 | ||
17424665 DM |
1118 | $changes = 1 if $self->rewrite_config_file( |
1119 | 'main.cf.in', '/etc/postfix/main.cf'); | |
1120 | ||
1121 | $changes = 1 if $self->rewrite_config_file( | |
1122 | 'master.cf.in', '/etc/postfix/master.cf'); | |
1123 | ||
f609bf7f DM |
1124 | #rewrite_config_transports ($class); |
1125 | #rewrite_config_whitelist ($class); | |
1126 | #rewrite_config_tls_policy ($class); | |
1127 | ||
1128 | # make sure aliases.db is up to date | |
1129 | system('/usr/bin/newaliases'); | |
17424665 DM |
1130 | |
1131 | return $changes; | |
f609bf7f DM |
1132 | } |
1133 | ||
f983300f | 1134 | sub rewrite_config { |
c248d69f DM |
1135 | my ($self, $restart_services) = @_; |
1136 | ||
1137 | if ($self->rewrite_config_postfix() && $restart_services) { | |
1138 | PMG::Utils::service_cmd('postfix', 'restart'); | |
1139 | } | |
1140 | ||
1141 | if ($self->rewrite_dot_forward() && $restart_services) { | |
1142 | # no need to restart anything | |
1143 | } | |
1144 | ||
1145 | if ($self->rewrite_config_postgres() && $restart_services) { | |
1146 | # do nothing (too many side effects)? | |
1147 | # does not happen anyways, because config does not change. | |
1148 | } | |
f983300f | 1149 | |
c248d69f DM |
1150 | if ($self->rewrite_config_spam() && $restart_services) { |
1151 | PMG::Utils::service_cmd('pmg-smtp-filter', 'restart'); | |
1152 | } | |
1153 | ||
1154 | if ($self->rewrite_config_clam() && $restart_services) { | |
8f87fe74 | 1155 | PMG::Utils::service_cmd('clamav-daemon', 'restart'); |
c248d69f DM |
1156 | } |
1157 | ||
1158 | if ($self->rewrite_config_freshclam() && $restart_services) { | |
8f87fe74 | 1159 | PMG::Utils::service_cmd('clamav-freshclam', 'restart'); |
c248d69f | 1160 | } |
17424665 | 1161 | |
f983300f DM |
1162 | } |
1163 | ||
7e0e6dbe | 1164 | 1; |