First Shot
Signed-off-by: Patrick Niebeling <patrick.niebeling@adacor.com>
This commit is contained in:
174
Stable2.0/conf/dynmaps/aliasexp.php
Normal file
174
Stable2.0/conf/dynmaps/aliasexp.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
// File size is limited by Nginx site to 10M
|
||||
// To speed things up, we do not include prerequisites
|
||||
header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
// Do not show errors, we log to using error_log
|
||||
ini_set('error_reporting', 0);
|
||||
// Init database
|
||||
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
|
||||
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
error_log("ALIASEXP: " . $e . PHP_EOL);
|
||||
http_response_code(501);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
|
||||
function parse_email($email) {
|
||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
||||
$a = strrpos($email, '@');
|
||||
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
|
||||
}
|
||||
if (!function_exists('getallheaders')) {
|
||||
function getallheaders() {
|
||||
if (!is_array($_SERVER)) {
|
||||
return array();
|
||||
}
|
||||
$headers = array();
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
|
||||
// Read headers
|
||||
$headers = getallheaders();
|
||||
// Get rcpt
|
||||
$rcpt = $headers['Rcpt'];
|
||||
// Remove tag
|
||||
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
||||
// Parse email address
|
||||
$parsed_rcpt = parse_email($rcpt);
|
||||
// Create array of final mailboxes
|
||||
$rcpt_final_mailboxes = array();
|
||||
|
||||
// Skip if not a mailcow handled domain
|
||||
try {
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
error_log("ALIASEXP: " . $e . PHP_EOL);
|
||||
http_response_code(504);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Always assume rcpt is not a final mailbox but an alias for a mailbox or further aliases
|
||||
//
|
||||
// rcpt
|
||||
// |
|
||||
// mailbox <-- goto ---> alias1, alias2, mailbox2
|
||||
// | |
|
||||
// mailbox3 |
|
||||
// |
|
||||
// alias3 ---> mailbox4
|
||||
//
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
|
||||
$stmt->execute(array(
|
||||
':rcpt' => $rcpt
|
||||
));
|
||||
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
||||
if (empty($gotos)) {
|
||||
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :rcpt AND `active` = '1'");
|
||||
$stmt->execute(array(
|
||||
':rcpt' => '@' . $parsed_rcpt['domain']
|
||||
));
|
||||
$gotos = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
||||
}
|
||||
if (empty($gotos)) {
|
||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :rcpt AND `active` = '1'");
|
||||
$stmt->execute(array(':rcpt' => $parsed_rcpt['domain']));
|
||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
||||
if ($goto_branch) {
|
||||
$gotos = $parsed_rcpt['local'] . '@' . $goto_branch;
|
||||
}
|
||||
}
|
||||
$gotos_array = explode(',', $gotos);
|
||||
|
||||
$loop_c = 0;
|
||||
|
||||
while (count($gotos_array) != 0 && $loop_c <= 20) {
|
||||
|
||||
// Loop through all found gotos
|
||||
foreach ($gotos_array as $index => &$goto) {
|
||||
error_log("ALIAS EXPANDER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
|
||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
|
||||
$stmt->execute(array(':goto' => $goto));
|
||||
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
|
||||
if (!empty($username)) {
|
||||
error_log("ALIAS EXPANDER: http pipe: mailbox found: " . $username . PHP_EOL);
|
||||
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
|
||||
if (!in_array($username, $rcpt_final_mailboxes)) {
|
||||
$rcpt_final_mailboxes[] = $username;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$parsed_goto = parse_email($goto);
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||
error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
|
||||
$stmt->execute(array(':goto' => $goto));
|
||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
||||
if ($goto_branch) {
|
||||
error_log("ALIAS EXPANDER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
|
||||
$goto_branch_array = explode(',', $goto_branch);
|
||||
} else {
|
||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` AND '1'");
|
||||
$stmt->execute(array(':domain' => $parsed_goto['domain']));
|
||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
||||
if ($goto_branch) {
|
||||
error_log("ALIAS EXPANDER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
|
||||
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// goto item was processed, unset
|
||||
unset($gotos_array[$index]);
|
||||
}
|
||||
|
||||
// Merge goto branch array derived from previous loop (if any), filter duplicates and unset goto branch array
|
||||
if (!empty($goto_branch_array)) {
|
||||
$gotos_array = array_unique(array_merge($gotos_array, $goto_branch_array));
|
||||
unset($goto_branch_array);
|
||||
}
|
||||
|
||||
// Reindex array
|
||||
$gotos_array = array_values($gotos_array);
|
||||
|
||||
// Force exit if loop cannot be solved
|
||||
// Postfix does not allow for alias loops, so this should never happen.
|
||||
$loop_c++;
|
||||
error_log("ALIAS EXPANDER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
|
||||
}
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
error_log("ALIAS EXPANDER: " . $e->getMessage() . PHP_EOL);
|
||||
http_response_code(502);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Does also return the mailbox name if question == answer (query == mailbox)
|
||||
if (count($rcpt_final_mailboxes) == 1) {
|
||||
error_log("ALIASEXP: direct alias " . $rcpt . " expanded to " . $rcpt_final_mailboxes[0] . PHP_EOL);
|
||||
echo trim($rcpt_final_mailboxes[0]);
|
||||
}
|
88
Stable2.0/conf/dynmaps/bcc.php
Normal file
88
Stable2.0/conf/dynmaps/bcc.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// File size is limited by Nginx site to 10M
|
||||
// To speed things up, we do not include prerequisites
|
||||
header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
// Do not show errors, we log to using error_log
|
||||
ini_set('error_reporting', 0);
|
||||
// Init database
|
||||
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
|
||||
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
error_log("BCC MAP SQL ERROR: " . $e . PHP_EOL);
|
||||
http_response_code(501);
|
||||
exit;
|
||||
}
|
||||
|
||||
function parse_email($email) {
|
||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
||||
$a = strrpos($email, '@');
|
||||
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
|
||||
}
|
||||
if (!function_exists('getallheaders')) {
|
||||
function getallheaders() {
|
||||
if (!is_array($_SERVER)) {
|
||||
return array();
|
||||
}
|
||||
$headers = array();
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
|
||||
// Read headers
|
||||
$headers = getallheaders();
|
||||
// Get rcpt
|
||||
$rcpt = $headers['Rcpt'];
|
||||
// Get from
|
||||
$from = $headers['From'];
|
||||
// Remove tags
|
||||
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
||||
$from = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $from);
|
||||
|
||||
try {
|
||||
if (!empty($rcpt)) {
|
||||
$stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'rcpt' AND `local_dest` = :local_dest AND `active` = '1'");
|
||||
$stmt->execute(array(
|
||||
':local_dest' => $rcpt
|
||||
));
|
||||
$bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest'];
|
||||
if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
error_log("BCC MAP: returning ". $bcc_dest . " for " . $rcpt . PHP_EOL);
|
||||
http_response_code(201);
|
||||
echo trim($bcc_dest);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
if (!empty($from)) {
|
||||
$stmt = $pdo->prepare("SELECT `bcc_dest` FROM `bcc_maps` WHERE `type` = 'sender' AND `local_dest` = :local_dest AND `active` = '1'");
|
||||
$stmt->execute(array(
|
||||
':local_dest' => $from
|
||||
));
|
||||
$bcc_dest = $stmt->fetch(PDO::FETCH_ASSOC)['bcc_dest'];
|
||||
if (!empty($bcc_dest) && filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
|
||||
error_log("BCC MAP: returning ". $bcc_dest . " for " . $from . PHP_EOL);
|
||||
http_response_code(201);
|
||||
echo trim($bcc_dest);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
error_log("BCC MAP SQL ERROR: " . $e->getMessage() . PHP_EOL);
|
||||
http_response_code(502);
|
||||
exit;
|
||||
}
|
||||
|
113
Stable2.0/conf/dynmaps/footer.php
Normal file
113
Stable2.0/conf/dynmaps/footer.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
// File size is limited by Nginx site to 10M
|
||||
// To speed things up, we do not include prerequisites
|
||||
header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
// Do not show errors, we log to using error_log
|
||||
ini_set('error_reporting', 0);
|
||||
// Init database
|
||||
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
|
||||
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
error_log("FOOTER: " . $e . PHP_EOL);
|
||||
http_response_code(501);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!function_exists('getallheaders')) {
|
||||
function getallheaders() {
|
||||
if (!is_array($_SERVER)) {
|
||||
return array();
|
||||
}
|
||||
$headers = array();
|
||||
foreach ($_SERVER as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||
}
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
|
||||
// Read headers
|
||||
$headers = getallheaders();
|
||||
// Get Domain
|
||||
$domain = $headers['Domain'];
|
||||
// Get Username
|
||||
$username = $headers['Username'];
|
||||
// Get From
|
||||
$from = $headers['From'];
|
||||
// define empty footer
|
||||
$empty_footer = json_encode(array(
|
||||
'html' => '',
|
||||
'plain' => '',
|
||||
'skip_replies' => 0,
|
||||
'vars' => array()
|
||||
));
|
||||
|
||||
error_log("FOOTER: checking for domain " . $domain . ", user " . $username . " and address " . $from . PHP_EOL);
|
||||
|
||||
try {
|
||||
// try get $target_domain if $domain is an alias_domain
|
||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
|
||||
WHERE `alias_domain` = :alias_domain");
|
||||
$stmt->execute(array(
|
||||
':alias_domain' => $domain
|
||||
));
|
||||
$alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$alias_domain) {
|
||||
$target_domain = $domain;
|
||||
} else {
|
||||
$target_domain = $alias_domain['target_domain'];
|
||||
}
|
||||
|
||||
// get footer associated with the domain
|
||||
$stmt = $pdo->prepare("SELECT `plain`, `html`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer`
|
||||
WHERE `domain` = :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => $target_domain
|
||||
));
|
||||
$footer = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// check if the sender is excluded
|
||||
if (in_array($from, json_decode($footer['mbox_exclude']))){
|
||||
$footer = false;
|
||||
}
|
||||
if (in_array($domain, json_decode($footer['alias_domain_exclude']))){
|
||||
$footer = false;
|
||||
}
|
||||
if (empty($footer)){
|
||||
echo $empty_footer;
|
||||
exit;
|
||||
}
|
||||
error_log("FOOTER: " . json_encode($footer) . PHP_EOL);
|
||||
|
||||
// footer will be applied
|
||||
// get custom mailbox attributes to insert into the footer
|
||||
$stmt = $pdo->prepare("SELECT `custom_attributes` FROM `mailbox` WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
$custom_attributes = $stmt->fetch(PDO::FETCH_ASSOC)['custom_attributes'];
|
||||
if (empty($custom_attributes)){
|
||||
$custom_attributes = (object)array();
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
error_log("FOOTER: " . $e->getMessage() . PHP_EOL);
|
||||
http_response_code(502);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// return footer
|
||||
$footer["vars"] = $custom_attributes;
|
||||
echo json_encode($footer);
|
57
Stable2.0/conf/dynmaps/forwardinghosts.php
Normal file
57
Stable2.0/conf/dynmaps/forwardinghosts.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
header('Content-Type: text/plain');
|
||||
ini_set('error_reporting', 0);
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
|
||||
function in_net($addr, $net) {
|
||||
$net = explode('/', $net);
|
||||
if (count($net) > 1) {
|
||||
$mask = $net[1];
|
||||
}
|
||||
$net = inet_pton($net[0]);
|
||||
$addr = inet_pton($addr);
|
||||
$length = strlen($net); // 4 for IPv4, 16 for IPv6
|
||||
if (strlen($net) != strlen($addr)) {
|
||||
return false;
|
||||
}
|
||||
if (!isset($mask)) {
|
||||
$mask = $length * 8;
|
||||
}
|
||||
$addr_bin = '';
|
||||
$net_bin = '';
|
||||
for ($i = 0; $i < $length; ++$i) {
|
||||
$addr_bin .= str_pad(decbin(ord(substr($addr, $i, $i+1))), 8, '0', STR_PAD_LEFT);
|
||||
$net_bin .= str_pad(decbin(ord(substr($net, $i, $i+1))), 8, '0', STR_PAD_LEFT);
|
||||
}
|
||||
return substr($addr_bin, 0, $mask) == substr($net_bin, 0, $mask);
|
||||
}
|
||||
|
||||
if (isset($_GET['host'])) {
|
||||
try {
|
||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
if (in_net($_GET['host'], $host)) {
|
||||
echo '200 PERMIT';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
echo '200 DUNNO';
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
echo '200 DUNNO';
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
echo '240.240.240.240' . PHP_EOL;
|
||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
echo $host . PHP_EOL;
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
echo '240.240.240.240' . PHP_EOL;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
2
Stable2.0/conf/dynmaps/index.html
Normal file
2
Stable2.0/conf/dynmaps/index.html
Normal file
@ -0,0 +1,2 @@
|
||||
<html>
|
||||
</html>
|
2
Stable2.0/conf/dynmaps/sasl_logs.php
Normal file
2
Stable2.0/conf/dynmaps/sasl_logs.php
Normal file
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// PoC
|
471
Stable2.0/conf/dynmaps/settings.php
Normal file
471
Stable2.0/conf/dynmaps/settings.php
Normal file
@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/*
|
||||
The match section performs AND operation on different matches: for example, if you have from and rcpt in the same rule,
|
||||
then the rule matches only when from AND rcpt match. For similar matches, the OR rule applies: if you have multiple rcpt matches,
|
||||
then any of these will trigger the rule. If a rule is triggered then no more rules are matched.
|
||||
*/
|
||||
header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
// Getting headers sent by the client.
|
||||
ini_set('error_reporting', 0);
|
||||
|
||||
//$dsn = $database_type . ':host=' . $database_host . ';dbname=' . $database_name;
|
||||
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
$stmt = $pdo->query("SELECT '1' FROM `filterconf`");
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
echo 'settings { }';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if db changed and return header
|
||||
$stmt = $pdo->prepare("SELECT GREATEST(COALESCE(MAX(UNIX_TIMESTAMP(UPDATE_TIME)), 1), COALESCE(MAX(UNIX_TIMESTAMP(CREATE_TIME)), 1)) AS `db_update_time` FROM `information_schema`.`tables`
|
||||
WHERE (`TABLE_NAME` = 'filterconf' OR `TABLE_NAME` = 'settingsmap' OR `TABLE_NAME` = 'sogo_quick_contact' OR `TABLE_NAME` = 'alias')
|
||||
AND TABLE_SCHEMA = :dbname;");
|
||||
$stmt->execute(array(
|
||||
':dbname' => $database_name
|
||||
));
|
||||
$db_update_time = $stmt->fetch(PDO::FETCH_ASSOC)['db_update_time'];
|
||||
if (empty($db_update_time)) {
|
||||
$db_update_time = 1572048000;
|
||||
}
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $db_update_time)) {
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 304);
|
||||
exit;
|
||||
} else {
|
||||
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $db_update_time).' GMT', true, 200);
|
||||
}
|
||||
|
||||
function parse_email($email) {
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
||||
$a = strrpos($email, '@');
|
||||
return array('local' => substr($email, 0, $a), 'domain' => substr($email, $a));
|
||||
}
|
||||
|
||||
function normalize_email($email) {
|
||||
$email = strtolower(str_replace('/', '\/', $email));
|
||||
$gm = "@gmail.com";
|
||||
if (substr_compare($email, $gm, -strlen($gm)) == 0) {
|
||||
$email = explode('@', $email);
|
||||
$email[0] = str_replace('.', '', $email[0]);
|
||||
$email = implode('@', $email);
|
||||
}
|
||||
$gm_alt = "@googlemail.com";
|
||||
if (substr_compare($email, $gm_alt, -strlen($gm_alt)) == 0) {
|
||||
$email = explode('@', $email);
|
||||
$email[0] = str_replace('.', '', $email[0]);
|
||||
$email[1] = str_replace('@', '', $gm);
|
||||
$email = implode('@', $email);
|
||||
}
|
||||
if (str_contains($email, "+")) {
|
||||
$email = explode('@', $email);
|
||||
$user = explode('+', $email[0]);
|
||||
$email[0] = $user[0];
|
||||
$email = implode('@', $email);
|
||||
}
|
||||
return $email;
|
||||
}
|
||||
|
||||
function wl_by_sogo() {
|
||||
global $pdo;
|
||||
$rcpt = array();
|
||||
$stmt = $pdo->query("SELECT DISTINCT(`sogo_folder_info`.`c_path2`) AS `user`, GROUP_CONCAT(`sogo_quick_contact`.`c_mail`) AS `contacts` FROM `sogo_folder_info`
|
||||
INNER JOIN `sogo_quick_contact` ON `sogo_quick_contact`.`c_folder_id` = `sogo_folder_info`.`c_folder_id`
|
||||
GROUP BY `c_path2`");
|
||||
$sogo_contacts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($sogo_contacts)) {
|
||||
foreach (explode(',', $row['contacts']) as $contact) {
|
||||
if (!filter_var($contact, FILTER_VALIDATE_EMAIL)) {
|
||||
continue;
|
||||
}
|
||||
// Explicit from, no mime_from, no regex - envelope must match
|
||||
// mailcow white and blacklists also cover mime_from
|
||||
$rcpt[$row['user']][] = normalize_email($contact);
|
||||
}
|
||||
}
|
||||
return $rcpt;
|
||||
}
|
||||
|
||||
function ucl_rcpts($object, $type) {
|
||||
global $pdo;
|
||||
$rcpt = array();
|
||||
if ($type == 'mailbox') {
|
||||
// Standard aliases
|
||||
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
|
||||
WHERE `goto` = :object_goto
|
||||
AND `address` NOT LIKE '@%'");
|
||||
$stmt->execute(array(
|
||||
':object_goto' => $object
|
||||
));
|
||||
$standard_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($standard_aliases)) {
|
||||
$local = parse_email($row['address'])['local'];
|
||||
$domain = parse_email($row['address'])['domain'];
|
||||
if (!empty($local) && !empty($domain)) {
|
||||
$rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i';
|
||||
}
|
||||
$rcpt[] = str_replace('/', '\/', $row['address']);
|
||||
}
|
||||
// Aliases by alias domains
|
||||
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox`
|
||||
LEFT OUTER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain`
|
||||
WHERE `mailbox`.`username` = :object");
|
||||
$stmt->execute(array(
|
||||
':object' => $object
|
||||
));
|
||||
$by_domain_aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($by_domain_aliases);
|
||||
while ($row = array_shift($by_domain_aliases)) {
|
||||
if (!empty($row['alias'])) {
|
||||
$local = parse_email($row['alias'])['local'];
|
||||
$domain = parse_email($row['alias'])['domain'];
|
||||
if (!empty($local) && !empty($domain)) {
|
||||
$rcpt[] = '/^' . str_replace('/', '\/', $local) . '[+].*' . str_replace('/', '\/', $domain) . '$/i';
|
||||
}
|
||||
$rcpt[] = str_replace('/', '\/', $row['alias']);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($type == 'domain') {
|
||||
// Domain self
|
||||
$rcpt[] = '/.*@' . $object . '/i';
|
||||
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
|
||||
WHERE `target_domain` = :object");
|
||||
$stmt->execute(array(':object' => $object));
|
||||
$alias_domains = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
array_filter($alias_domains);
|
||||
while ($row = array_shift($alias_domains)) {
|
||||
$rcpt[] = '/.*@' . $row['alias_domain'] . '/i';
|
||||
}
|
||||
}
|
||||
return $rcpt;
|
||||
}
|
||||
?>
|
||||
settings {
|
||||
watchdog {
|
||||
priority = 10;
|
||||
rcpt_mime = "/null@localhost/i";
|
||||
from_mime = "/watchdog@localhost/i";
|
||||
apply "default" {
|
||||
symbols_disabled = ["HISTORY_SAVE", "ARC", "ARC_SIGNED", "DKIM", "DKIM_SIGNED", "CLAM_VIRUS"];
|
||||
want_spam = yes;
|
||||
actions {
|
||||
reject = 9999.0;
|
||||
greylist = 9998.0;
|
||||
"add header" = 9997.0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
/*
|
||||
// Start custom scores for users
|
||||
*/
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'highspamlevel' OR `option` = 'lowspamlevel'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
score_<?=$username_sane;?> {
|
||||
priority = 4;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf`
|
||||
WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel')
|
||||
AND `object`= :object");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$spamscore = $stmt->fetchAll(PDO::FETCH_COLUMN|PDO::FETCH_GROUP);
|
||||
?>
|
||||
apply "default" {
|
||||
actions {
|
||||
reject = <?=$spamscore['highspamlevel'][0];?>;
|
||||
greylist = <?=$spamscore['lowspamlevel'][0] - 1;?>;
|
||||
"add header" = <?=$spamscore['lowspamlevel'][0];?>;
|
||||
}
|
||||
}
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start SOGo contacts whitelist
|
||||
// Priority 4, lower than a domain whitelist (5) and lower than a mailbox whitelist (6)
|
||||
*/
|
||||
|
||||
foreach (wl_by_sogo() as $user => $contacts) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $user);
|
||||
?>
|
||||
whitelist_sogo_<?=$username_sane;?> {
|
||||
<?php
|
||||
foreach ($contacts as $contact) {
|
||||
?>
|
||||
from = <?=json_encode($contact, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
priority = 4;
|
||||
<?php
|
||||
foreach (ucl_rcpts($user, 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
SOGO_CONTACT = -99.0;
|
||||
}
|
||||
symbols [
|
||||
"SOGO_CONTACT"
|
||||
]
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start whitelist
|
||||
*/
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'whitelist_from'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
whitelist_<?=$username_sane;?> {
|
||||
<?php
|
||||
$list_items = array();
|
||||
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
AND `option` = 'whitelist_from'");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$list_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($list_items as $item) {
|
||||
?>
|
||||
from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
|
||||
<?php
|
||||
}
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
priority = 5;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = 6;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
MAILCOW_WHITE = -999.0;
|
||||
}
|
||||
symbols [
|
||||
"MAILCOW_WHITE"
|
||||
]
|
||||
}
|
||||
whitelist_mime_<?=$username_sane;?> {
|
||||
<?php
|
||||
foreach ($list_items as $item) {
|
||||
?>
|
||||
from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
|
||||
<?php
|
||||
}
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
priority = 5;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = 6;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
MAILCOW_WHITE = -999.0;
|
||||
}
|
||||
symbols [
|
||||
"MAILCOW_WHITE"
|
||||
]
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start blacklist
|
||||
*/
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT `object` FROM `filterconf` WHERE `option` = 'blacklist_from'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['object']);
|
||||
?>
|
||||
blacklist_<?=$username_sane;?> {
|
||||
<?php
|
||||
$list_items = array();
|
||||
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf`
|
||||
WHERE `object`= :object
|
||||
AND `option` = 'blacklist_from'");
|
||||
$stmt->execute(array(':object' => $row['object']));
|
||||
$list_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($list_items as $item) {
|
||||
?>
|
||||
from = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
|
||||
<?php
|
||||
}
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
priority = 5;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = 6;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
MAILCOW_BLACK = 999.0;
|
||||
}
|
||||
symbols [
|
||||
"MAILCOW_BLACK"
|
||||
]
|
||||
}
|
||||
blacklist_header_<?=$username_sane;?> {
|
||||
<?php
|
||||
foreach ($list_items as $item) {
|
||||
?>
|
||||
from_mime = "/<?='^' . str_replace('\*', '.*', preg_quote($item['value'], '/')) . '$' ;?>/i";
|
||||
<?php
|
||||
}
|
||||
if (!filter_var(trim($row['object']), FILTER_VALIDATE_EMAIL)) {
|
||||
?>
|
||||
priority = 5;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
else {
|
||||
?>
|
||||
priority = 6;
|
||||
<?php
|
||||
foreach (ucl_rcpts($row['object'], strpos($row['object'], '@') === FALSE ? 'domain' : 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
apply "default" {
|
||||
MAILCOW_BLACK = 999.0;
|
||||
}
|
||||
symbols [
|
||||
"MAILCOW_BLACK"
|
||||
]
|
||||
}
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
// Start traps
|
||||
*/
|
||||
|
||||
?>
|
||||
ham_trap {
|
||||
<?php
|
||||
foreach (ucl_rcpts('ham@localhost', 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
priority = 9;
|
||||
apply "default" {
|
||||
symbols_enabled = ["HISTORY_SAVE"];
|
||||
}
|
||||
symbols [
|
||||
"HAM_TRAP"
|
||||
]
|
||||
}
|
||||
|
||||
spam_trap {
|
||||
<?php
|
||||
foreach (ucl_rcpts('spam@localhost', 'mailbox') as $rcpt) {
|
||||
?>
|
||||
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
priority = 9;
|
||||
apply "default" {
|
||||
symbols_enabled = ["HISTORY_SAVE"];
|
||||
}
|
||||
symbols [
|
||||
"SPAM_TRAP"
|
||||
]
|
||||
}
|
||||
<?php
|
||||
// Start additional content
|
||||
|
||||
$stmt = $pdo->query("SELECT `id`, `content` FROM `settingsmap` WHERE `active` = '1'");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($rows)) {
|
||||
$username_sane = preg_replace("/[^a-zA-Z0-9]+/", "", $row['id']);
|
||||
?>
|
||||
additional_settings_<?=intval($row['id']);?> {
|
||||
<?php
|
||||
$content = preg_split('/\r\n|\r|\n/', $row['content']);
|
||||
foreach ($content as $line) {
|
||||
echo ' ' . $line . PHP_EOL;
|
||||
}
|
||||
?>
|
||||
}
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
}
|
6
Stable2.0/conf/dynmaps/vars.inc.php
Normal file
6
Stable2.0/conf/dynmaps/vars.inc.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
require_once('../../../web/inc/vars.inc.php');
|
||||
if (file_exists('../../../web/inc/vars.local.inc.php')) {
|
||||
include_once('../../../web/inc/vars.local.inc.php');
|
||||
}
|
||||
?>
|
Reference in New Issue
Block a user