Merge remote-tracking branch 'origin/dev' into forwardinghosts

master
Michael Kuron 2017-04-22 18:13:58 +02:00
commit 08612f0aef
14 changed files with 818 additions and 194 deletions

View File

@ -1,8 +1,8 @@
FROM debian:latest
FROM debian:stretch-slim
MAINTAINER https://m-ko.de Markus Kosmal <code@cnfg.io>
# Debian Base to use
ENV DEBIAN_VERSION jessie
ENV DEBIAN_VERSION stretch
# initial install of av daemon
RUN echo "deb http://http.debian.net/debian/ $DEBIAN_VERSION main contrib non-free" > /etc/apt/sources.list && \
@ -13,15 +13,14 @@ RUN echo "deb http://http.debian.net/debian/ $DEBIAN_VERSION main contrib non-fr
clamav-daemon \
clamav-freshclam \
libclamunrar7 \
wget && \
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# initial update of av databases
RUN wget -O /var/lib/clamav/main.cvd http://db.local.clamav.net/main.cvd && \
wget -O /var/lib/clamav/daily.cvd http://db.local.clamav.net/daily.cvd && \
wget -O /var/lib/clamav/bytecode.cvd http://db.local.clamav.net/bytecode.cvd && \
chown clamav:clamav /var/lib/clamav/*.cvd
COPY dl_files.sh /dl_files.sh
RUN chmod +x /dl_files.sh
RUN /dl_files.sh
# permission juggling
RUN mkdir /var/run/clamav && \
@ -33,9 +32,6 @@ RUN sed -i 's/^Foreground .*$/Foreground true/g' /etc/clamav/clamd.conf && \
echo "TCPSocket 3310" >> /etc/clamav/clamd.conf && \
sed -i 's/^Foreground .*$/Foreground true/g' /etc/clamav/freshclam.conf
# volume provision
VOLUME ["/var/lib/clamav"]
# port provision
EXPOSE 3310

View File

@ -1,35 +1,7 @@
#!/bin/bash
# bootstrap clam av service and clam av database updater shell script
# presented by mko (Markus Kosmal<code@cnfg.io>)
set -m
trap "kill 0" SIGINT
# start clam service itself and the updater in background as daemon
freshclam -d &
clamd &
# recognize PIDs
pidlist=`jobs -p`
# initialize latest result var
latest_exit=0
# define shutdown helper
function shutdown() {
trap "" SUBS
for single in $pidlist; do
if ! kill -0 $pidlist 2>/dev/null; then
wait $pidlist
exitcode=$?
fi
done
kill $pidlist 2>/dev/null
}
# run shutdown
trap terminate SUBS
wait
# return received result
exit $latest_exit
sleep inf

View File

@ -0,0 +1,32 @@
#!/bin/bash
declare -a DB_MIRRORS=(
"switch.clamav.net"
"clamavdb.heanet.ie"
"clamav.iol.cz"
"clamav.univ-nantes.fr"
"clamav.easynet.fr"
"clamav.begi.net"
)
declare -a DB_MIRRORS=( $(shuf -e "${DB_MIRRORS[@]}") )
DB_FILES=(
"bytecode.cvd"
"daily.cvd"
"main.cvd"
)
for i in "${DB_MIRRORS[@]}"; do
for j in "${DB_FILES[@]}"; do
[[ -f "/var/lib/clamav/${j}" && -s "/var/lib/clamav/${j}" ]] && continue;
if [[ $(curl -o /dev/null --connect-timeout 1 \
--max-time 1 \
--silent \
--head \
--write-out "%{http_code}\n" "${i}/${j}") == 200 ]]; then
curl "${i}/${j}" -o "/var/lib/clamav/${j}" -#
fi
done
done
chown clamav:clamav /var/lib/clamav/*.cvd

View File

@ -231,8 +231,11 @@ while ($row = array_shift($rows)) {
}
?>
apply "default" {
MAILCOW_MOO = -999.0;
MAILCOW_WHITE = -999.0;
}
symbols [
"MAILCOW_WHITE"
]
}
<?php
}
@ -326,10 +329,13 @@ while ($row = array_shift($rows)) {
}
?>
apply "default" {
MAILCOW_MOO = 999.0;
MAILCOW_BLACK = 999.0;
}
symbols [
"MAILCOW_BLACK"
]
}
<?php
}
?>
}
}

View File

@ -0,0 +1,8 @@
clamav {
attachments_only = false;
max_size = 20000000;
symbol = "CLAM_VIRUS";
type = "clamav";
log_clean = true;
servers = "clamd:3310";
}

View File

@ -0,0 +1,7 @@
rules {
DKIM_FAIL {
action = "add header";
expression = "R_DKIM_REJECT & !MAILLIST & !MAILCOW_WHITE & !MAILCOW_BLACK";
require_action = ["no action", "greylist"];
}
}

View File

@ -7,10 +7,6 @@ rspamd_config.MAILCOW_AUTH = {
end
}
rspamd_config.MAILCOW_MOO = function (task)
return true
end
modify_subject_map = rspamd_config:add_map({
url = 'http://172.22.1.251:8081/tags.php',
type = 'map',

View File

@ -62,76 +62,6 @@ function hasMailboxObjectAccess($username, $role, $object) {
}
return false;
}
function init_db_schema() {
// This will be much better in future releases...
global $pdo;
try {
$stmt = $pdo->prepare("SELECT NULL FROM `admin`, `imapsync`, `tfa`");
$stmt->execute();
}
catch (Exception $e) {
$lines = file('/web/inc/init.sql');
$data = '';
foreach ($lines as $line) {
if (substr($line, 0, 2) == '--' || $line == '') {
continue;
}
$data .= $line;
if (substr(trim($line), -1, 1) == ';') {
$pdo->query($data);
$data = '';
}
}
// Create index if not exists
$stmt = $pdo->query("SHOW INDEX FROM sogo_acl WHERE KEY_NAME = 'sogo_acl_c_folder_id_idx'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("CREATE INDEX sogo_acl_c_folder_id_idx ON sogo_acl(c_folder_id)");
}
$stmt = $pdo->query("SHOW INDEX FROM sogo_acl WHERE KEY_NAME = 'sogo_acl_c_uid_idx'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("CREATE INDEX sogo_acl_c_uid_idx ON sogo_acl(c_uid)");
}
$_SESSION['return'] = array(
'type' => 'success',
'msg' => 'Database initialization completed.'
);
}
// Add newly added tables
$stmt = $pdo->query("CREATE TABLE IF NOT EXISTS `forwarding_hosts` (`host` VARCHAR(255) NOT NULL, PRIMARY KEY (`host`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC");
// Add newly added columns
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'kind'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `kind` VARCHAR(100) NOT NULL DEFAULT ''");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'multiple_bookings'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `multiple_bookings` tinyint(1) NOT NULL DEFAULT '0'");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `imapsync` LIKE 'delete1'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `imapsync` ADD `delete1` tinyint(1) NOT NULL DEFAULT '0'");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE 'wants_tagged_subject'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `mailbox` ADD `wants_tagged_subject` tinyint(1) NOT NULL DEFAULT '0'");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `tfa` LIKE 'key_id'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `tfa` ADD `key_id` VARCHAR(255) DEFAULT 'unidentified'");
}
$stmt = $pdo->query("SHOW COLUMNS FROM `forwarding_hosts` LIKE 'source'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `forwarding_hosts` ADD `source` VARCHAR(255) DEFAULT ''");
}
}
function verify_ssha256($hash, $password) {
// Remove tag if any
$hash = ltrim($hash, '{SSHA256}');
@ -294,13 +224,11 @@ function edit_admin_account($postarray) {
$password_hashed = hash_password($password);
try {
$stmt = $pdo->prepare("UPDATE `admin` SET
`modified` = :modified,
`password` = :password_hashed,
`username` = :username1
WHERE `username` = :username2");
$stmt->execute(array(
':password_hashed' => $password_hashed,
':modified' => date('Y-m-d H:i:s'),
':username1' => $username,
':username2' => $username_now
));
@ -316,12 +244,10 @@ function edit_admin_account($postarray) {
else {
try {
$stmt = $pdo->prepare("UPDATE `admin` SET
`modified` = :modified,
`username` = :username1
WHERE `username` = :username2");
$stmt->execute(array(
':username1' => $username,
':modified' => date('Y-m-d H:i:s'),
':username2' => $username_now
));
}
@ -615,10 +541,9 @@ function edit_user_account($postarray) {
}
$password_hashed = hash_password($password_new);
try {
$stmt = $pdo->prepare("UPDATE `mailbox` SET `modified` = :modified, `password` = :password_hashed WHERE `username` = :username");
$stmt = $pdo->prepare("UPDATE `mailbox` SET `password` = :password_hashed WHERE `username` = :username");
$stmt->execute(array(
':password_hashed' => $password_hashed,
':modified' => date('Y-m-d H:i:s'),
':username' => $username
));
}
@ -1640,13 +1565,11 @@ function add_domain_admin($postarray) {
}
}
try {
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `created`, `modified`, `active`)
VALUES (:username, :password_hashed, '0', :created, :modified, :active)");
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
VALUES (:username, :password_hashed, '0', :active)");
$stmt->execute(array(
':username' => $username,
':password_hashed' => $password_hashed,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
}
@ -2235,12 +2158,11 @@ function edit_domain_admin($postarray) {
}
$password_hashed = hash_password($password);
try {
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username1, `modified` = :modified, `active` = :active, `password` = :password_hashed WHERE `username` = :username2");
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username1, `active` = :active, `password` = :password_hashed WHERE `username` = :username2");
$stmt->execute(array(
':password_hashed' => $password_hashed,
':username1' => $username,
':username2' => $username_now,
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
if (isset($postarray['disable_tfa'])) {
@ -2262,11 +2184,10 @@ function edit_domain_admin($postarray) {
}
else {
try {
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username1, `modified` = :modified, `active` = :active WHERE `username` = :username2");
$stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username1, `active` = :active WHERE `username` = :username2");
$stmt->execute(array(
':username1' => $username,
':username2' => $username_now,
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
if (isset($postarray['disable_tfa'])) {
@ -2328,10 +2249,9 @@ function edit_domain_admin($postarray) {
}
$password_hashed = hash_password($password_new);
try {
$stmt = $pdo->prepare("UPDATE `admin` SET `modified` = :modified, `password` = :password_hashed WHERE `username` = :username");
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
$stmt->execute(array(
':password_hashed' => $password_hashed,
':modified' => date('Y-m-d H:i:s'),
':username' => $username
));
}
@ -2363,7 +2283,7 @@ function get_admin_details() {
return false;
}
try {
$stmt = $pdo->prepare("SELECT `username`, `modified`, `created` FROM `admin`WHERE `superadmin`='1' AND active='1'");
$stmt = $pdo->prepare("SELECT `username`, `modified`, `created` FROM `admin` WHERE `superadmin`='1' AND active='1'");
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
}
@ -2608,8 +2528,8 @@ function mailbox_add_domain($postarray) {
}
try {
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `maxquota`, `quota`, `transport`, `backupmx`, `created`, `modified`, `active`, `relay_all_recipients`)
VALUES (:domain, :description, :aliases, :mailboxes, :maxquota, :quota, 'virtual', :backupmx, :created, :modified, :active, :relay_all_recipients)");
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `maxquota`, `quota`, `transport`, `backupmx`, `active`, `relay_all_recipients`)
VALUES (:domain, :description, :aliases, :mailboxes, :maxquota, :quota, 'virtual', :backupmx, :active, :relay_all_recipients)");
$stmt->execute(array(
':domain' => $domain,
':description' => $description,
@ -2619,8 +2539,6 @@ function mailbox_add_domain($postarray) {
':quota' => $quota,
':backupmx' => $backupmx,
':active' => $active,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':relay_all_recipients' => $relay_all_recipients
));
$_SESSION['return'] = array(
@ -2796,16 +2714,14 @@ function mailbox_add_alias($postarray) {
$goto = implode(",", $gotos);
try {
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `created`, `modified`, `active`)
VALUES (:address, :goto, :domain, :created, :modified, :active)");
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
VALUES (:address, :goto, :domain, :active)");
if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
$stmt->execute(array(
':address' => '@'.$domain,
':goto' => $goto,
':domain' => $domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
}
@ -2814,8 +2730,6 @@ function mailbox_add_alias($postarray) {
':address' => $address,
':goto' => $goto,
':domain' => $domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
}
@ -2916,13 +2830,11 @@ function mailbox_add_alias_domain($postarray) {
}
try {
$stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `created`, `modified`, `active`)
VALUES (:alias_domain, :target_domain, :created, :modified, :active)");
$stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
VALUES (:alias_domain, :target_domain, :active)");
$stmt->execute(array(
':alias_domain' => $alias_domain,
':target_domain' => $target_domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
$_SESSION['return'] = array(
@ -3125,8 +3037,8 @@ function mailbox_add_mailbox($postarray) {
}
try {
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `created`, `modified`, `active`)
VALUES (:username, :password_hashed, :name, :maildir, :quota_b, :local_part, :domain, :created, :modified, :active)");
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `active`)
VALUES (:username, :password_hashed, :name, :maildir, :quota_b, :local_part, :domain, :active)");
$stmt->execute(array(
':username' => $username,
':password_hashed' => $password_hashed,
@ -3135,8 +3047,6 @@ function mailbox_add_mailbox($postarray) {
':quota_b' => $quota_b,
':local_part' => $local_part,
':domain' => $domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
@ -3144,14 +3054,12 @@ function mailbox_add_mailbox($postarray) {
VALUES (:username, '0', '0')");
$stmt->execute(array(':username' => $username));
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `created`, `modified`, `active`)
VALUES (:username1, :username2, :domain, :created, :modified, :active)");
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
VALUES (:username1, :username2, :domain, :active)");
$stmt->execute(array(
':username1' => $username,
':username2' => $username,
':domain' => $domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
@ -3281,15 +3189,13 @@ function mailbox_add_resource($postarray) {
}
try {
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `created`, `modified`, `active`, `multiple_bookings`, `kind`)
VALUES (:name, 'RESOURCE', :description, 'RESOURCE', 0, :local_part, :domain, :created, :modified, :active, :multiple_bookings, :kind)");
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`)
VALUES (:name, 'RESOURCE', :description, 'RESOURCE', 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
$stmt->execute(array(
':name' => $name,
':description' => $description,
':local_part' => $local_part,
':domain' => $domain,
':created' => date('Y-m-d H:i:s'),
':modified' => date('Y-m-d H:i:s'),
':active' => $active,
':kind' => $kind,
':multiple_bookings' => $multiple_bookings
@ -3380,12 +3286,10 @@ function mailbox_edit_alias_domain($postarray) {
try {
$stmt = $pdo->prepare("UPDATE `alias_domain` SET
`alias_domain` = :alias_domain,
`active` = :active,
`modified` = :modified
`active` = :active
WHERE `alias_domain` = :alias_domain_now");
$stmt->execute(array(
':alias_domain' => $alias_domain,
':modified' => date('Y-m-d H:i:s'),
':alias_domain_now' => $alias_domain_now,
':active' => $active
));
@ -3461,14 +3365,12 @@ function mailbox_edit_alias($postarray) {
try {
$stmt = $pdo->prepare("UPDATE `alias` SET
`goto` = :goto,
`active`= :active,
`modified` = :modified
`active`= :active
WHERE `address` = :address");
$stmt->execute(array(
':goto' => $goto,
':active' => $active,
':address' => $address,
':modified' => date('Y-m-d H:i:s'),
':address' => $address
));
$_SESSION['return'] = array(
'type' => 'success',
@ -3513,11 +3415,9 @@ function mailbox_edit_domain($postarray) {
isset($postarray['active']) ? $active = '1' : $active = '0';
try {
$stmt = $pdo->prepare("UPDATE `domain` SET
`modified`= :modified,
`description` = :description
WHERE `domain` = :domain");
$stmt->execute(array(
':modified' => date('Y-m-d H:i:s'),
':description' => $description,
':domain' => $domain
));
@ -3621,7 +3521,6 @@ function mailbox_edit_domain($postarray) {
}
try {
$stmt = $pdo->prepare("UPDATE `domain` SET
`modified`= :modified,
`relay_all_recipients` = :relay_all_recipients,
`backupmx` = :backupmx,
`active` = :active,
@ -3639,7 +3538,6 @@ function mailbox_edit_domain($postarray) {
':maxquota' => $maxquota,
':mailboxes' => $mailboxes,
':aliases' => $aliases,
':modified' => date('Y-m-d H:i:s'),
':description' => $description,
':domain' => $domain
));
@ -3851,23 +3749,19 @@ function mailbox_edit_mailbox($postarray) {
$password_hashed = hash_password($password);
try {
$stmt = $pdo->prepare("UPDATE `alias` SET
`modified` = :modified,
`active` = :active
WHERE `address` = :address");
$stmt->execute(array(
':address' => $username,
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
$stmt = $pdo->prepare("UPDATE `mailbox` SET
`modified` = :modified,
`active` = :active,
`password` = :password_hashed,
`name`= :name,
`quota` = :quota_b
WHERE `username` = :username");
$stmt->execute(array(
':modified' => date('Y-m-d H:i:s'),
':password_hashed' => $password_hashed,
':active' => $active,
':name' => $name,
@ -3890,23 +3784,19 @@ function mailbox_edit_mailbox($postarray) {
}
try {
$stmt = $pdo->prepare("UPDATE `alias` SET
`modified` = :modified,
`active` = :active
WHERE `address` = :address");
$stmt->execute(array(
':address' => $username,
':modified' => date('Y-m-d H:i:s'),
':active' => $active
));
$stmt = $pdo->prepare("UPDATE `mailbox` SET
`modified` = :modified,
`active` = :active,
`name`= :name,
`quota` = :quota_b
WHERE `username` = :username");
$stmt->execute(array(
':active' => $active,
':modified' => date('Y-m-d H:i:s'),
':name' => $name,
':quota_b' => $quota_b,
':username' => $username
@ -3969,7 +3859,6 @@ function mailbox_edit_resource($postarray) {
try {
$stmt = $pdo->prepare("UPDATE `mailbox` SET
`modified` = :modified,
`active` = :active,
`name`= :description,
`kind`= :kind,
@ -3977,7 +3866,6 @@ function mailbox_edit_resource($postarray) {
WHERE `username` = :name");
$stmt->execute(array(
':active' => $active,
':modified' => date('Y-m-d H:i:s'),
':description' => $description,
':multiple_bookings' => $multiple_bookings,
':kind' => $kind,
@ -4803,12 +4691,10 @@ function mailbox_delete_mailbox($postarray) {
}
$gotos_rebuild = implode(',', $goto_exploded);
$stmt = $pdo->prepare("UPDATE `alias` SET
`goto` = :goto,
`modified` = :modified,
`goto` = :goto
WHERE `address` = :address");
$stmt->execute(array(
':goto' => $gotos_rebuild,
':modified' => date('Y-m-d H:i:s'),
':address' => $gotos['address']
));
}

View File

@ -0,0 +1,596 @@
<?php
function init_db_schema() {
try {
global $pdo;
$db_version = "20042017_1926";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->query("SELECT `version` FROM `versions`");
if ($stmt->fetch(PDO::FETCH_ASSOC)['version'] == $db_version) {
return true;
}
}
$views = array(
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
SELECT goto, IFNULL(GROUP_CONCAT(address SEPARATOR ' '), '') AS address FROM alias
WHERE address!=goto
AND active = '1'
AND address NOT LIKE '@%'
GROUP BY goto;",
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as FROM sender_acl
WHERE send_as NOT LIKE '@%'
GROUP BY logged_in_as;",
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
LEFT OUTER JOIN alias_domain on target_domain=domain GROUP BY username;"
);
$tables = array(
"versions" => array(
"cols" => array(
"application" => "VARCHAR(255) NOT NULL",
"version" => "VARCHAR(100) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
),
"keys" => array(
"primary" => array(
"" => array("application")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"admin" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"password" => "VARCHAR(255) NOT NULL",
"superadmin" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE NOW(0)",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"alias" => array(
"cols" => array(
"address" => "VARCHAR(255) NOT NULL",
"goto" => "TEXT NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("address")
),
"key" => array(
"domain" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sender_acl" => array(
"cols" => array(
"logged_in_as" => "VARCHAR(255) NOT NULL",
"send_as" => "VARCHAR(255) NOT NULL"
),
"keys" => array(),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"domain" => array(
"cols" => array(
"domain" => "VARCHAR(255) NOT NULL",
"description" => "VARCHAR(255)",
"aliases" => "INT(10) NOT NULL DEFAULT '0'",
"mailboxes" => "INT(10) NOT NULL DEFAULT '0'",
"maxquota" => "BIGINT(20) NOT NULL DEFAULT '0'",
"quota" => "BIGINT(20) NOT NULL DEFAULT '0'",
"transport" => "VARCHAR(255) NOT NULL",
"backupmx" => "TINYINT(1) NOT NULL DEFAULT '0'",
"relay_all_recipients" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"alias_domain" => array(
"cols" => array(
"alias_domain" => "VARCHAR(255) NOT NULL",
"target_domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("alias_domain")
),
"key" => array(
"active" => array("active"),
"target_domain" => array("target_domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"spamalias" => array(
"cols" => array(
"address" => "VARCHAR(255) NOT NULL",
"goto" => "TEXT NOT NULL",
"validity" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("address")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"filterconf" => array(
"cols" => array(
"object" => "VARCHAR(255) NOT NULL DEFAULT ''",
"option" => "VARCHAR(50) NOT NULL DEFAULT ''",
"value" => "VARCHAR(100) NOT NULL DEFAULT ''",
"prefid" => "INT(11) NOT NULL AUTO_INCREMENT"
),
"keys" => array(
"primary" => array(
"" => array("prefid")
),
"key" => array(
"object" => array("object")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"quota2" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"bytes" => "BIGINT(20) NOT NULL DEFAULT '0'",
"messages" => "BIGINT(20) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"mailbox" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"password" => "VARCHAR(255) NOT NULL",
"name" => "VARCHAR(255)",
"maildir" => "VARCHAR(255) NOT NULL",
"quota" => "BIGINT(20) NOT NULL DEFAULT '0'",
"local_part" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"tls_enforce_in" => "TINYINT(1) NOT NULL DEFAULT '0'",
"tls_enforce_out" => "TINYINT(1) NOT NULL DEFAULT '0'",
"kind" => "VARCHAR(100) NOT NULL DEFAULT ''",
"multiple_bookings" => "TINYINT(1) NOT NULL DEFAULT '0'",
"wants_tagged_subject" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("username")
),
"key" => array(
"domain" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"domain_admins" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"key" => array(
"username" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"imapsync" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"user2" => "VARCHAR(255) NOT NULL",
"host1" => "VARCHAR(255) NOT NULL",
"authmech1" => "ENUM('PLAIN','LOGIN','CRAM-MD5') DEFAULT 'PLAIN'",
"regextrans2" => "VARCHAR(255) DEFAULT ''",
"authmd51" => "TINYINT(1) NOT NULL DEFAULT 0",
"domain2" => "VARCHAR(255) NOT NULL DEFAULT ''",
"subfolder2" => "VARCHAR(255) NOT NULL DEFAULT ''",
"user1" => "VARCHAR(255) NOT NULL",
"password1" => "VARCHAR(255) NOT NULL",
"exclude" => "VARCHAR(500) NOT NULL DEFAULT ''",
"maxage" => "SMALLINT NOT NULL DEFAULT '0'",
"mins_interval" => "VARCHAR(50) NOT NULL",
"port1" => "SMALLINT NOT NULL",
"enc1" => "ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS'",
"delete2duplicates" => "TINYINT(1) NOT NULL DEFAULT '1'",
"returned_text" => "TEXT",
"last_run" => "TIMESTAMP NULL DEFAULT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"tfa" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"username" => "VARCHAR(255) NOT NULL",
"authmech" => "ENUM('yubi_otp', 'u2f', 'hotp', 'totp')",
"secret" => "VARCHAR(255) DEFAULT NULL",
"keyHandle" => "VARCHAR(255) DEFAULT NULL",
"publicKey" => "VARCHAR(255) DEFAULT NULL",
"counter" => "INT NOT NULL DEFAULT '0'",
"certificate" => "TEXT",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"forwarding_hosts" => array(
"cols" => array(
"host" => "VARCHAR(255) NOT NULL",
"source" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("host")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_acl" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_object" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_role" => "VARCHAR(80) NOT NULL"
),
"keys" => array(
"key" => array(
"sogo_acl_c_folder_id_idx" => array("c_folder_id"),
"sogo_acl_c_uid_idx" => array("c_uid")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_alarms_folder" => array(
"cols" => array(
"c_path" => "VARCHAR(255) NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_recurrence_id" => "INT(11) DEFAULT NULL",
"c_alarm_number" => "INT(11) NOT NULL",
"c_alarm_date" => "INT(11) NOT NULL"
),
"keys" => array(),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_cache_folder" => array(
"cols" => array(
"c_uid" => "VARCHAR(255) NOT NULL",
"c_path" => "VARCHAR(255) NOT NULL",
"c_parent_path" => "VARCHAR(255) DEFAULT NULL",
"c_type" => "TINYINT(3) unsigned NOT NULL",
"c_creationdate" => "INT(11) NOT NULL",
"c_lastmodified" => "INT(11) NOT NULL",
"c_version" => "INT(11) NOT NULL DEFAULT '0'",
"c_deleted" => "TINYINT(4) NOT NULL DEFAULT '0'",
"c_content" => "LONGTEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_uid", "c_path")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_folder_info" => array(
"cols" => array(
"c_folder_id" => "BIGINT(20) unsigned NOT NULL AUTO_INCREMENT",
"c_path" => "VARCHAR(255) NOT NULL",
"c_path1" => "VARCHAR(255) NOT NULL",
"c_path2" => "VARCHAR(255) DEFAULT NULL",
"c_path3" => "VARCHAR(255) DEFAULT NULL",
"c_path4" => "VARCHAR(255) DEFAULT NULL",
"c_foldername" => "VARCHAR(255) NOT NULL",
"c_location" => "INT NULL",
"c_quick_location" => "VARCHAR(2048) DEFAULT NULL",
"c_acl_location" => "VARCHAR(2048) DEFAULT NULL",
"c_folder_type" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("c_path")
),
"unique" => array(
"c_folder_id" => array("c_folder_id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_quick_appointment" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_startdate" => "INT",
"c_enddate" => "INT",
"c_cycleenddate" => "INT",
"c_title" => "VARCHAR(1000) NOT NULL",
"c_participants" => "TEXT",
"c_isallday" => "INT",
"c_iscycle" => "INT",
"c_cycleinfo" => "TEXT",
"c_classification" => "INT NOT NULL",
"c_isopaque" => "INT NOT NULL",
"c_status" => "INT NOT NULL",
"c_priority" => "INT",
"c_location" => "VARCHAR(255)",
"c_orgmail" => "VARCHAR(255)",
"c_partmails" => "TEXT",
"c_partstates" => "TEXT",
"c_category" => "VARCHAR(255)",
"c_sequence" => "INT",
"c_component" => "VARCHAR(10) NOT NULL",
"c_nextalarm" => "INT",
"c_description" => "TEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_quick_contact" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_givenname" => "VARCHAR(255)",
"c_cn" => "VARCHAR(255)",
"c_sn" => "VARCHAR(255)",
"c_screenname" => "VARCHAR(255)",
"c_l" => "VARCHAR(255)",
"c_mail" => "VARCHAR(255)",
"c_o" => "VARCHAR(255)",
"c_ou" => "VARCHAR(255)",
"c_telephonenumber" => "VARCHAR(255)",
"c_categories" => "VARCHAR(255)",
"c_component" => "VARCHAR(10) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_sessions_folder" => array(
"cols" => array(
"c_id" => "VARCHAR(255) NOT NULL",
"c_value" => "VARCHAR(255) NOT NULL",
"c_creationdate" => "INT(11) NOT NULL",
"c_lastseen" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("c_id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_store" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_content" => "MEDIUMTEXT NOT NULL",
"c_creationdate" => "INT NOT NULL",
"c_lastmodified" => "INT NOT NULL",
"c_version" => "INT NOT NULL",
"c_deleted" => "INT"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_user_profile" => array(
"cols" => array(
"c_uid" => "VARCHAR(255) NOT NULL",
"c_defaults" => "TEXT",
"c_settings" => "TEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_uid")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
)
);
foreach ($tables as $table => $properties) {
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
foreach($properties['cols'] as $column => $type) {
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("ALTER TABLE `" . $table . "` ADD `" . $column . "` " . $type);
}
else {
$pdo->query("ALTER TABLE `" . $table . "` MODIFY COLUMN `" . $column . "` " . $type);
}
}
foreach($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = 'PRIMARY'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP PRIMARY KEY, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD PRIMARY KEY (" . $fields . ")");
}
}
if (strtolower($key_type) == 'key') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP INDEX `" . $key_name . "`, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD KEY `" . $key_name . "` (" . $fields . ")");
}
}
if (strtolower($key_type) == 'unique') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP INDEX `" . $key_name . "`, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD UNIQUE KEY `" . $key_name . "` (" . $fields . ")");
}
}
}
// Drop all vanished columns
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "`");
$cols_in_table = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($cols_in_table)) {
if (!array_key_exists($row['Field'], $properties['cols'])) {
$pdo->query("ALTER TABLE `" . $table . "` DROP COLUMN `" . $row['Field'] . "`;");
}
}
// Step 1: Get all non-primary keys, that currently exist and those that should exist
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE `Key_name` != 'PRIMARY'");
$keys_in_table = $stmt->fetchAll(PDO::FETCH_ASSOC);
$keys_to_exist = array();
if (isset($properties['keys']['unique']) && is_array($properties['keys']['unique'])) {
foreach ($properties['keys']['unique'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name;
}
}
if (isset($properties['keys']['key']) && is_array($properties['keys']['key'])) {
foreach ($properties['keys']['key'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name;
}
}
// Step 2: Drop all vanished indexes
while ($row = array_shift($keys_in_table)) {
if (!in_array($row['Key_name'], $keys_to_exist)) {
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $row['Key_name'] . "`");
}
}
// Step 3: Drop all vanished primary keys
if (!isset($properties['keys']['primary'])) {
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = 'PRIMARY'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$pdo->query("ALTER TABLE `" . $table . "` DROP PRIMARY KEY");
}
}
}
else {
// Create table if it is missing
$sql = "CREATE TABLE IF NOT EXISTS `" . $table . "` (";
foreach($properties['cols'] as $column => $type) {
$sql .= $column . " " . $type . ",";
}
foreach($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "PRIMARY KEY (" . $fields . ")" . ",";
}
}
elseif (strtolower($key_type) == 'key') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "KEY `" . $key_name . "` (" . $fields . ")" . ",";
}
}
elseif (strtolower($key_type) == 'unique') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "UNIQUE KEY `" . $key_name . "` (" . $fields . ")" . ",";
}
}
}
$sql = rtrim($sql, ",");
$sql .= ") " . $properties['attr'];
$pdo->query($sql);
}
// Reset table attributes
$pdo->query("ALTER TABLE `" . $table . "` " . $properties['attr'] . ";");
}
// Recreate SQL views
foreach ($views as $view => $create) {
$pdo->query("DROP VIEW IF EXISTS `" . $view . "`;");
$pdo->query($create);
}
// Inject admin if not exists
$stmt = $pdo->query("INSERT INTO `admin` (`username`, `password`, `superadmin`, `created`, `modified`, `active`)
SELECT 'admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1
WHERE NOT EXISTS (SELECT * FROM `admin`);");
$stmt = $pdo->query("DELETE FROM `domain_admins`;");
$stmt = $pdo->query("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
SELECT `username`, 'ALL', NOW(), 1 FROM `admin`
WHERE superadmin='1' AND `username` NOT IN (SELECT `username` FROM `domain_admins`);");
// Insert new DB schema version
$stmt = $pdo->query("REPLACE INTO `versions` (`application`, `version`) VALUES ('db_schema', '" . $db_version . "');");
$_SESSION['return'] = array(
'type' => 'success',
'msg' => 'Database initialisation completed'
);
}
catch (PDOException $e) {
$_SESSION['return'] = array(
'type' => 'danger',
'msg' => 'Database initialisation failed: ' . $e->getMessage()
);
}
}
?>

View File

@ -29,18 +29,28 @@ require_once 'inc/lib/U2F.php';
$u2f = new u2flib_server\U2F('https://' . $_SERVER['SERVER_NAME']);
// PDO
$dsn = "$database_type:host=$database_host;dbname=$database_name";
// Calculate offset
$now = new DateTime();
$mins = $now->getOffset() / 60;
$sgn = ($mins < 0 ? -1 : 1);
$mins = abs($mins);
$hrs = floor($mins / 60);
$mins -= $hrs * 60;
$offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);
$dsn = $database_type . ":host=" . $database_host . ";dbname=" . $database_name;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone = '" . $offset . "'",
];
try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
}
catch (PDOException $e) {
?>
<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>🐮 Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>?? Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
<?php
exit;
}
@ -106,5 +116,6 @@ if (isset($_GET['lang'])) {
require_once 'lang/lang.en.php';
include 'lang/lang.'.$_SESSION['mailcow_locale'].'.php';
require_once 'inc/functions.inc.php';
require_once 'inc/init_db.inc.php';
require_once 'inc/triggers.inc.php';
(!isset($_SESSION['mailcow_cc_username'])) ? init_db_schema() : null;
init_db_schema();

View File

@ -158,6 +158,84 @@ docker-compose exec postfix-mailcow chmod 660 /opt/postfix/conf/smarthost_passwd
docker-compose exec postfix-mailcow postfix reload
```
## Optional: Log to Syslog
Enable Rsyslog to receive logs on 524/tcp:
```
# This setting depends on your Rsyslog version and configuration format.
# For most Debian derivates it will work like this...
$ModLoad imtcp
$TCPServerAddress 127.0.0.1
$InputTCPServerRun 524
# ...while for Ubuntu 16.04 it looks like this:
module(load="imtcp")
input(type="imtcp" address="127.0.0.1" port="524")
# No matter your Rsyslog version, you should set this option to off
# if you plan to use Fail2ban
$RepeatedMsgReduction off
```
Restart rsyslog after enabling the TCP listener.
Now setup Docker daemon to start with the syslog driver.
This enables the syslog driver for all containers!
Debian users can change the startup configuration in `/etc/default/docker` while CentOS users find it in `/etc/sysconfig/docker`:
```
...
DOCKER_OPTS="--log-driver=syslog --log-opt syslog-address=tcp://127.0.0.1:524"
...
```
**Caution:** For some reason Ubuntu 16.04 and some, but not all, systemd based distros do not read the defaults file parameters.
Just run `systemctl edit docker.service` and add the following content to fix it.
**Note:** If "systemctl edit" is not available, just copy the content to `/etc/systemd/system/docker.service.d/override.conf`.
The first empty ExecStart parameter is not a mistake.
```
[Service]
EnvironmentFile=/etc/default/docker
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// $DOCKER_OPTS
```
Restart the Docker daemon and run `docker-compose down && docker-compose up -d` to recreate the containers.
### Use Fail2ban
**This is a subsection of "Log to Syslog", which is required for Fail2ban to work.**
Open `/etc/fail2ban/filter.d/common.conf` and search for the prefix_line parameter, change it to ".*":
```
__prefix_line = .*
```
Create `/etc/fail2ban/jail.d/dovecot.conf`...
```
[dovecot]
enabled = true
filter = dovecot
logpath = /var/log/syslog
chain = FORWARD
```
and `jail.d/postfix-sasl.conf`:
```
[postfix-sasl]
enabled = true
filter = postfix-sasl
logpath = /var/log/syslog
chain = FORWARD
```
Restart Fail2ban.
## Install a local MTA

View File

@ -1,6 +1,8 @@
# mailcow: dockerized - 🐮 + 🐋 = 💕
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JWBSYHF4SMC68)
[![Servercow](https://www.servercow.de/img/cow_globe_200.svg)](https://www.servercow.de)
If you want to support mailcow, consider hosting mailcow on a Servercow virtual machine @ Servercow!
## Screenshots
@ -30,6 +32,7 @@ mailcow dockerized comes with **11 containers** linked in **one bridged network*
- mysql-vol-1
- rspamd-vol-1
- postfix-vol-1
- crypt-vol-1
The integrated **mailcow UI** allows administrative work on your mail server instance as well as separated domain administrator and mailbox user access:

View File

@ -75,7 +75,7 @@ Beware that a mailbox user can login to mailcow and override a domain policy fil
Make your changes in `data/Dockerfiles/$service` and build the image locally:
```
docker build data/Dockerfiles/service -t andryyy/mailcow-dockerized:$service
docker build data/Dockerfiles/service -t mailcow/$service
```
Now auto-recreate modified containers:
@ -311,14 +311,11 @@ Running `docker-compose down -v` will **destroy all mailcow: dockerized volumes*
## Reset admin password
Reset mailcow admin to `admin:moohoo`:
1\. Drop admin table
```
source mailcow.conf
docker-compose exec mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TABLE admin;"
cd mailcow_path
bash reset_admin.sh
```
2\. Open mailcow UI to auto-init the db
## Rspamd
### Learn spam and ham

36
reset_admin.sh 100644
View File

@ -0,0 +1,36 @@
#/bin/bash
if [[ ! -f mailcow.conf ]]; then
echo "Cannot find mailcow.conf, make sure this script is run from within the mailcow folder."
exit 1
fi
echo -n "Checking MySQL service... "
docker-compose ps -q mysql-mailcow > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "failed"
echo "MySQL (mysql-mailcow) is not up and running, exiting..."
exit 1
fi
echo "OK"
read -r -p "Are you sure you want to reset the mailcow administrator account? [y/N] " response
response=${response,,} # tolower
if [[ "$response" =~ ^(yes|y)$ ]]; then
echo -e "\nWorking, please wait..."
source mailcow.conf
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin;"
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, created, modified, active) VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1);"
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO domain_admins (username, domain, created, active) VALUES ('admin', 'ALL', NOW(), 1);"
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';"
echo "
Reset credentials:
---
Username: admin
Password: moohoo
TFA: none
"
else
echo "Operation canceled."
fi