Skip to content

Commit fa56dcd

Browse files
committed
verify recipient addrs for amavis from downstream smtpd
1 parent 8ed9a0a commit fa56dcd

File tree

6 files changed

+157
-109
lines changed

6 files changed

+157
-109
lines changed

install/lib/installer_base.lib.php

Lines changed: 89 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,7 +1107,7 @@ public function configure_postfix($options = '') {
11071107
$server_ini_array = ini_to_array(stripslashes($server_ini_rec['config']));
11081108
unset($server_ini_rec);
11091109

1110-
//* If there are RBL's defined, format the list and add them to smtp_recipient_restrictions to prevent removeal after an update
1110+
//* If there are RBL's defined, format the list and add them to smtp_recipient_restrictions to prevent removal after an update
11111111
$rbl_list = '';
11121112
if (@isset($server_ini_array['mail']['realtime_blackhole_list']) && $server_ini_array['mail']['realtime_blackhole_list'] != '') {
11131113
$rbl_hosts = explode(",", str_replace(" ", "", $server_ini_array['mail']['realtime_blackhole_list']));
@@ -1647,6 +1647,12 @@ public function configure_dovecot() {
16471647
public function configure_amavis() {
16481648
global $conf;
16491649

1650+
//* These postconf commands will be executed on installation and update
1651+
$server_ini_rec = $this->db->queryOneRecord("SELECT mail_server, config FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . '.server', $conf['server_id']);
1652+
$server_ini_array = ini_to_array(stripslashes($server_ini_rec['config']));
1653+
$mail_server = ($server_ini_rec['mail_server']) ? true : false;
1654+
unset($server_ini_rec);
1655+
16501656
// amavisd user config file
16511657
$configfile = 'amavisd_user_config';
16521658
if(is_file($conf['amavis']['config_dir'].'/conf.d/50-user')) copy($conf['amavis']['config_dir'].'/conf.d/50-user', $conf['amavis']['config_dir'].'/50-user~');
@@ -1660,63 +1666,85 @@ public function configure_amavis() {
16601666
wf($conf['amavis']['config_dir'].'/conf.d/50-user', $content);
16611667
chmod($conf['amavis']['config_dir'].'/conf.d/50-user', 0640);
16621668

1663-
// TODO: chmod and chown on the config file
1669+
$mail_config = $server_ini_array['mail'];
1670+
//* only change postfix config if amavisd is active filter
1671+
if($mail_server && $mail_config['content_filter'] === 'amavisd') {
1672+
// test if lmtp if available
1673+
$configure_lmtp = $this->get_postfix_service('lmtp','unix');
16641674

1665-
// test if lmtp if available
1666-
$configure_lmtp = $this->get_postfix_service('lmtp','unix');
1675+
// Adding the amavisd commands to the postfix configuration
1676+
$postconf_commands = array ();
16671677

1668-
// Adding the amavisd commands to the postfix configuration
1669-
// Add array for no error in foreach and maybe future options
1670-
$postconf_commands = array ();
1678+
// Check for amavisd -> pure webserver with postfix for mailing without antispam
1679+
if ($conf['amavis']['installed']) {
1680+
$content_filter_service = ($configure_lmtp) ? 'lmtp' : 'amavis';
1681+
$postconf_commands[] = "content_filter = ${content_filter_service}:[127.0.0.1]:10024";
1682+
$postconf_commands[] = 'receive_override_options = no_address_mappings';
1683+
$postconf_commands[] = 'address_verify_virtual_transport = smtp:[127.0.0.1]:10025';
1684+
$postconf_commands[] = 'address_verify_transport_maps = static:smtp:[127.0.0.1]:10025';
1685+
}
16711686

1672-
// Check for amavisd -> pure webserver with postfix for mailing without antispam
1673-
if ($conf['amavis']['installed']) {
1674-
$content_filter_service = ($configure_lmtp) ? 'lmtp' : 'amavis';
1675-
$postconf_commands[] = "content_filter = ${content_filter_service}:[127.0.0.1]:10024";
1676-
$postconf_commands[] = 'receive_override_options = no_address_mappings';
1677-
}
1687+
$options = preg_split("/,\s*/", exec("postconf -h smtpd_recipient_restrictions"));
1688+
$new_options = array();
1689+
foreach ($options as $value) {
1690+
$value = trim($value);
1691+
if ($value == '') continue;
1692+
if (preg_match("|check_recipient_access\s+proxy:mysql:${quoted_config_dir}/mysql-verify_recipients.cf|", $value)) {
1693+
continue;
1694+
}
1695+
$new_options[] = $value;
1696+
}
1697+
if ($configure_lmtp) {
1698+
for ($i = 0; isset($new_options[$i]); $i++) {
1699+
if ($new_options[$i] == 'reject_unlisted_recipient') {
1700+
array_splice($new_options, $i+1, 0, array("check_recipient_access proxy:mysql:${config_dir}/mysql-verify_recipients.cf"));
1701+
break;
1702+
}
1703+
}
1704+
# postfix < 3.3 needs this when using reject_unverified_recipient:
1705+
if(version_compare($postfix_version, 3.3, '<')) {
1706+
$postconf_commands[] = "enable_original_recipient = yes";
1707+
}
1708+
}
1709+
$postconf_commands[] = "smtpd_recipient_restrictions = ".implode(", ", $new_options);
16781710

1679-
// Make a backup copy of the main.cf file
1680-
copy($conf['postfix']['config_dir'].'/main.cf', $conf['postfix']['config_dir'].'/main.cf~2');
1711+
// Make a backup copy of the main.cf file
1712+
copy($conf['postfix']['config_dir'].'/main.cf', $conf['postfix']['config_dir'].'/main.cf~2');
16811713

1682-
// Executing the postconf commands
1683-
foreach($postconf_commands as $cmd) {
1684-
$command = "postconf -e '$cmd'";
1685-
caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
1686-
}
1714+
// Executing the postconf commands
1715+
foreach($postconf_commands as $cmd) {
1716+
$command = "postconf -e '$cmd'";
1717+
caselog($command." &> /dev/null", __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
1718+
}
16871719

1688-
$config_dir = $conf['postfix']['config_dir'];
1720+
$config_dir = $conf['postfix']['config_dir'];
16891721

1690-
// Adding amavis-services to the master.cf file if the service does not already exists
1691-
// $add_amavis = !$this->get_postfix_service('amavis','unix');
1692-
// $add_amavis_10025 = !$this->get_postfix_service('127.0.0.1:10025','inet');
1693-
// $add_amavis_10027 = !$this->get_postfix_service('127.0.0.1:10027','inet');
1694-
//*TODO: check templates against existing postfix-services to make sure we use the template
1695-
1696-
// Or just remove the old service definitions and add them again?
1697-
$add_amavis = $this->remove_postfix_service('amavis','unix');
1698-
$add_amavis_10025 = $this->remove_postfix_service('127.0.0.1:10025','inet');
1699-
$add_amavis_10027 = $this->remove_postfix_service('127.0.0.1:10027','inet');
1700-
1701-
if ($add_amavis || $add_amavis_10025 || $add_amavis_10027) {
1702-
//* backup master.cf
1703-
if(is_file($config_dir.'/master.cf')) copy($config_dir.'/master.cf', $config_dir.'/master.cf~');
1704-
// adjust amavis-config
1705-
if($add_amavis) {
1706-
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis.master', 'tpl/master_cf_amavis.master');
1707-
af($config_dir.'/master.cf', $content);
1708-
unset($content);
1709-
}
1710-
if ($add_amavis_10025) {
1711-
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10025.master', 'tpl/master_cf_amavis10025.master');
1712-
af($config_dir.'/master.cf', $content);
1713-
unset($content);
1722+
// Adding amavis-services to the master.cf file if the service does not already exists
1723+
// (just remove the old service definitions and add them again)
1724+
$add_amavis = $this->remove_postfix_service('amavis','unix');
1725+
$add_amavis_10025 = $this->remove_postfix_service('127.0.0.1:10025','inet');
1726+
$add_amavis_10027 = $this->remove_postfix_service('127.0.0.1:10027','inet');
1727+
1728+
if ($add_amavis || $add_amavis_10025 || $add_amavis_10027) {
1729+
//* backup master.cf
1730+
if(is_file($config_dir.'/master.cf')) copy($config_dir.'/master.cf', $config_dir.'/master.cf~');
1731+
// adjust amavis-config
1732+
if($add_amavis) {
1733+
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis.master', 'tpl/master_cf_amavis.master');
1734+
af($config_dir.'/master.cf', $content);
1735+
unset($content);
1736+
}
1737+
if ($add_amavis_10025) {
1738+
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10025.master', 'tpl/master_cf_amavis10025.master');
1739+
af($config_dir.'/master.cf', $content);
1740+
unset($content);
1741+
}
1742+
if ($add_amavis_10027) {
1743+
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10027.master', 'tpl/master_cf_amavis10027.master');
1744+
af($config_dir.'/master.cf', $content);
1745+
unset($content);
1746+
}
17141747
}
1715-
if ($add_amavis_10027) {
1716-
$content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/master_cf_amavis10027.master', 'tpl/master_cf_amavis10027.master');
1717-
af($config_dir.'/master.cf', $content);
1718-
unset($content);
1719-
}
17201748
}
17211749

17221750
// Add the clamav user to the amavis group
@@ -1746,14 +1774,18 @@ public function configure_rspamd() {
17461774
global $conf;
17471775

17481776
//* These postconf commands will be executed on installation and update
1749-
$server_ini_rec = $this->db->queryOneRecord("SELECT config FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . '.server', $conf['server_id']);
1777+
$server_ini_rec = $this->db->queryOneRecord("SELECT mail_server, config FROM ?? WHERE server_id = ?", $conf["mysql"]["database"] . '.server', $conf['server_id']);
17501778
$server_ini_array = ini_to_array(stripslashes($server_ini_rec['config']));
1779+
$mail_server = ($server_ini_rec['mail_server']) ? true : false;
17511780
unset($server_ini_rec);
17521781

17531782
$mail_config = $server_ini_array['mail'];
1754-
if($mail_config['content_filter'] === 'rspamd') {
1755-
exec("postconf -X 'receive_override_options'");
1756-
exec("postconf -X 'content_filter'");
1783+
//* only change postfix config if rspamd is active filter
1784+
if($mail_server && $mail_config['content_filter'] === 'rspamd') {
1785+
exec("postconf -X receive_override_options");
1786+
exec("postconf -X content_filter");
1787+
exec("postconf -X address_verify_virtual_transport");
1788+
exec("postconf -X address_verify_transport_maps");
17571789

17581790
exec("postconf -e 'smtpd_milters = inet:localhost:11332'");
17591791
exec("postconf -e 'non_smtpd_milters = inet:localhost:11332'");
@@ -1804,6 +1836,9 @@ public function configure_rspamd() {
18041836
if (preg_match('/check_policy_service\s+inet:127.0.0.1:10023/', $value)) {
18051837
continue;
18061838
}
1839+
if (preg_match("|check_recipient_access\s+proxy:mysql:${quoted_config_dir}/mysql-verify_recipients.cf|", $value)) {
1840+
continue;
1841+
}
18071842
$new_options[] = $value;
18081843
}
18091844
exec("postconf -e 'smtpd_recipient_restrictions = ".implode(", ", $new_options)."'");

install/tpl/master_cf_amavis.master

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
amavis unix - - - - 2 smtp
33
-o smtp_data_done_timeout=1200
44
-o smtp_send_xforward_command=yes
5-
-o smtp_bind_address=
5+
-o smtp_bind_address=
66

install/tpl/master_cf_amavis10025.master

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@
1414
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
1515
-o smtp_send_xforward_command=yes
1616
-o disable_dns_lookups=yes
17+
-o address_verify_virtual_transport=$virtual_transport
18+
-o address_verify_transport_maps=$transport_maps
1719

install/tpl/master_cf_amavis10027.master

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
-o strict_rfc821_envelopes=yes
1414
-o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
1515
-o smtp_send_xforward_command=yes
16-
-o milter_default_action=accept
17-
-o milter_macro_daemon_name=ORIGINATING
1816
-o disable_dns_lookups=yes
17+
-o address_verify_virtual_transport=$virtual_transport
18+
-o address_verify_transport_maps=$transport_maps
19+
-o milter_default_action=accept
20+
-o milter_macro_daemon_name=ORIGINATING
1921

interface/lib/classes/validate_mail_relay_domain.inc.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ function get_error($errmsg) {
4545
function validate_domain($field_name, $field_value, $validator) {
4646
global $app, $conf;
4747

48-
if(empty($field_value) || $field_name != 'domain') return;
49-
50-
5148
if(isset($app->remoting_lib->primary_id)) {
5249
$id = $app->remoting_lib->primary_id;
5350
} else {
@@ -56,7 +53,7 @@ function validate_domain($field_name, $field_value, $validator) {
5653

5754
// mail_relay_domain.domain must be unique per server
5855
$sql = "SELECT relay_domain_id, domain FROM mail_relay_domain WHERE domain = ? AND server_id = ? AND relay_domain_id != ?";
59-
$domain_check = $app->db->queryOneRecord($sql, $field_value, $conf['server_id'], $id);
56+
$domain_check = $app->db->queryOneRecord($sql, $field_value, $app->tform_actions->dataRecord['server_id'], $id);
6057

6158
if($domain_check) return $this->get_error('domain_error_unique');
6259
}

server/plugins-available/postfix_server_plugin.inc.php

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ function update($event_name, $data) {
7272
global $app, $conf;
7373
$postfix_restart = false;
7474

75+
// Plugin should only run on mail servers
76+
if(! $data['new']['mail_server']) {
77+
$app->log("postfix_server_plugin: plugin is enabled but this server is not configured as a mail server.", LOGLEVEL_WARN);
78+
return false;
79+
}
80+
7581
// get the config
7682
$app->uses("getconf,system");
7783
$old_ini_data = $app->ini_parser->parse_ini_string($data['old']['config']);
@@ -341,6 +347,10 @@ function update($event_name, $data) {
341347
for ($i = 0; isset($new_options[$i]); $i++) {
342348
if ($new_options[$i] == 'reject_unlisted_recipient') {
343349
array_splice($new_options, $i+1, 0, array("check_recipient_access proxy:mysql:${quoted_postfix_config_dir}/mysql-verify_recipients.cf"));
350+
351+
$app->system->exec_safe("postconf -e ?", 'address_verify_virtual_transport = smtp:[127.0.0.1]:10025');
352+
$app->system->exec_safe("postconf -e ?", 'address_verify_transport_maps = static:smtp:[127.0.0.1]:10025');
353+
344354
break;
345355
}
346356
}
@@ -351,62 +361,64 @@ function update($event_name, $data) {
351361
}
352362
exec("postconf -e 'smtpd_recipient_restrictions = ".implode(", ", $new_options)."'");
353363

354-
if($mail_config['content_filter'] != $old_ini_data['mail']['content_filter']) {
355-
$rslm = ($mail_config['reject_sender_login_mismatch'] == 'y') ? "reject_sender_login_mismatch," : "";
356-
$raslm = ($mail_config['reject_sender_login_mismatch'] == 'y') ? "reject_authenticated_sender_login_mismatch," : "";
357-
358-
if($mail_config['content_filter'] == 'rspamd'){
359-
exec("postconf -X 'receive_override_options'");
360-
exec("postconf -X 'content_filter'");
364+
$rslm = ($mail_config['reject_sender_login_mismatch'] == 'y') ? "reject_sender_login_mismatch," : "";
365+
$raslm = ($mail_config['reject_sender_login_mismatch'] == 'y') ? "reject_authenticated_sender_login_mismatch," : "";
361366

362-
exec("postconf -e 'smtpd_milters = inet:localhost:11332'");
363-
exec("postconf -e 'non_smtpd_milters = inet:localhost:11332'");
364-
exec("postconf -e 'milter_protocol = 6'");
365-
exec("postconf -e 'milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}'");
366-
exec("postconf -e 'milter_default_action = accept'");
367+
if($mail_config['content_filter'] == 'rspamd'){
368+
exec("postconf -X 'receive_override_options'");
369+
exec("postconf -X 'content_filter'");
370+
exec("postconf -X address_verify_virtual_transport");
371+
exec("postconf -X address_verify_transport_maps");
367372

368-
exec("postconf -e 'smtpd_sender_restrictions = ${raslm} permit_mynetworks, check_sender_access proxy:mysql:/etc/postfix/mysql-virtual_sender.cf, ${rslm} permit_sasl_authenticated, reject_non_fqdn_sender, reject_unlisted_sender'");
373+
exec("postconf -e 'smtpd_milters = inet:localhost:11332'");
374+
exec("postconf -e 'non_smtpd_milters = inet:localhost:11332'");
375+
exec("postconf -e 'milter_protocol = 6'");
376+
exec("postconf -e 'milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}'");
377+
exec("postconf -e 'milter_default_action = accept'");
369378

379+
exec("postconf -e 'smtpd_sender_restrictions = ${raslm} permit_mynetworks, check_sender_access proxy:mysql:/etc/postfix/mysql-virtual_sender.cf, ${rslm} permit_sasl_authenticated, reject_non_fqdn_sender, reject_unlisted_sender'");
370380

371-
$new_options = array();
372-
$options = preg_split("/,\s*/", exec("postconf -h smtpd_recipient_restrictions"));
373-
foreach ($options as $key => $value) {
374-
$value = trim($value);
375-
if ($value == '') continue;
376-
if (preg_match('/check_policy_service\s+inet:127.0.0.1:10023/', $value)) {
377-
continue;
378-
}
379-
$new_options[] = $value;
380-
}
381-
exec("postconf -e 'smtpd_recipient_restrictions = ".implode(", ", $new_options)."'");
382-
383-
// get all domains that have dkim enabled
384-
if ( substr($mail_config['dkim_path'], strlen($mail_config['dkim_path'])-1) == '/' ) {
385-
$mail_config['dkim_path'] = substr($mail_config['dkim_path'], 0, strlen($mail_config['dkim_path'])-1);
381+
$new_options = array();
382+
$options = preg_split("/,\s*/", exec("postconf -h smtpd_recipient_restrictions"));
383+
foreach ($options as $key => $value) {
384+
$value = trim($value);
385+
if ($value == '') continue;
386+
if (preg_match('/check_policy_service\s+inet:127.0.0.1:10023/', $value)) {
387+
continue;
386388
}
387-
$dkim_domains = $app->db->queryAllRecords('SELECT `dkim_selector`, `domain` FROM `mail_domain` WHERE `dkim` = ? ORDER BY `domain` ASC', 'y');
388-
$fpp = fopen('/etc/rspamd/local.d/dkim_domains.map', 'w');
389-
$fps = fopen('/etc/rspamd/local.d/dkim_selectors.map', 'w');
390-
foreach($dkim_domains as $dkim_domain) {
391-
fwrite($fpp, $dkim_domain['domain'] . ' ' . $mail_config['dkim_path'] . '/' . $dkim_domain['domain'] . '.private' . "\n");
392-
fwrite($fps, $dkim_domain['domain'] . ' ' . $dkim_domain['dkim_selector'] . "\n");
389+
if (preg_match("|check_recipient_access\s+proxy:mysql:${quoted_postfix_config_dir}/mysql-verify_recipients.cf|", $value)) {
390+
continue;
393391
}
394-
fclose($fpp);
395-
fclose($fps);
396-
unset($dkim_domains);
397-
} else {
398-
exec("postconf -X 'smtpd_milters'");
399-
exec("postconf -X 'non_smtpd_milters'");
400-
exec("postconf -X 'milter_protocol'");
401-
exec("postconf -X 'milter_mail_macros'");
402-
exec("postconf -X 'milter_default_action'");
403-
404-
exec("postconf -e 'receive_override_options = no_address_mappings'");
405-
exec("postconf -e 'content_filter = " . ($configure_lmtp ? "lmtp" : "amavis" ) . ":[127.0.0.1]:10024'");
392+
$new_options[] = $value;
393+
}
394+
exec("postconf -e 'smtpd_recipient_restrictions = ".implode(", ", $new_options)."'");
406395

407-
// fixme: should read this from conf templates
408-
exec("postconf -e 'smtpd_sender_restrictions = ${raslm} check_sender_access regexp:/etc/postfix/tag_as_originating.re, permit_mynetworks, check_sender_access proxy:mysql:/etc/postfix/mysql-virtual_sender.cf, ${rslm} permit_sasl_authenticated, reject_non_fqdn_sender, reject_unlisted_sender, check_sender_access regexp:/etc/postfix/tag_as_foreign.re'");
396+
// get all domains that have dkim enabled
397+
if ( substr($mail_config['dkim_path'], strlen($mail_config['dkim_path'])-1) == '/' ) {
398+
$mail_config['dkim_path'] = substr($mail_config['dkim_path'], 0, strlen($mail_config['dkim_path'])-1);
399+
}
400+
$dkim_domains = $app->db->queryAllRecords('SELECT `dkim_selector`, `domain` FROM `mail_domain` WHERE `dkim` = ? ORDER BY `domain` ASC', 'y');
401+
$fpp = fopen('/etc/rspamd/local.d/dkim_domains.map', 'w');
402+
$fps = fopen('/etc/rspamd/local.d/dkim_selectors.map', 'w');
403+
foreach($dkim_domains as $dkim_domain) {
404+
fwrite($fpp, $dkim_domain['domain'] . ' ' . $mail_config['dkim_path'] . '/' . $dkim_domain['domain'] . '.private' . "\n");
405+
fwrite($fps, $dkim_domain['domain'] . ' ' . $dkim_domain['dkim_selector'] . "\n");
409406
}
407+
fclose($fpp);
408+
fclose($fps);
409+
unset($dkim_domains);
410+
} else {
411+
exec("postconf -X 'smtpd_milters'");
412+
exec("postconf -X 'non_smtpd_milters'");
413+
exec("postconf -X 'milter_protocol'");
414+
exec("postconf -X 'milter_mail_macros'");
415+
exec("postconf -X 'milter_default_action'");
416+
417+
exec("postconf -e 'receive_override_options = no_address_mappings'");
418+
exec("postconf -e 'content_filter = " . ($configure_lmtp ? "lmtp" : "amavis" ) . ":[127.0.0.1]:10024'");
419+
420+
// fixme: should read this from conf templates
421+
exec("postconf -e 'smtpd_sender_restrictions = ${raslm} check_sender_access regexp:/etc/postfix/tag_as_originating.re, permit_mynetworks, check_sender_access proxy:mysql:/etc/postfix/mysql-virtual_sender.cf, ${rslm} permit_sasl_authenticated, reject_non_fqdn_sender, reject_unlisted_sender, check_sender_access regexp:/etc/postfix/tag_as_foreign.re'");
410422
}
411423

412424
if($mail_config['content_filter'] == 'rspamd' && ($mail_config['rspamd_password'] != $old_ini_data['mail']['rspamd_password'] || $mail_config['content_filter'] != $old_ini_data['mail']['content_filter'])) {

0 commit comments

Comments
 (0)