From eeaa48a7294698e302eb4f80bb146c9984c39f89 Mon Sep 17 00:00:00 2001 From: andryyy Date: Tue, 12 Sep 2017 20:57:02 +0200 Subject: [PATCH 1/6] [PHP-FPM] Use valid user for mysqladmin ping [SOGo] Use valid user for mysqladmin ping --- data/Dockerfiles/phpfpm/docker-entrypoint.sh | 2 +- data/Dockerfiles/sogo/bootstrap-sogo.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/phpfpm/docker-entrypoint.sh b/data/Dockerfiles/phpfpm/docker-entrypoint.sh index 0b8b303e..8c986335 100755 --- a/data/Dockerfiles/phpfpm/docker-entrypoint.sh +++ b/data/Dockerfiles/phpfpm/docker-entrypoint.sh @@ -6,7 +6,7 @@ if [[ $(stat -c %U /data/dkim/) != "www-data" ]] ; then chown -R www-data:www-da # Wait for containers -while ! mysqladmin ping --host mysql --silent; do +while ! mysqladmin ping --host mysql -u${DBUSER} -p${DBPASS} --silent; do sleep 2 done diff --git a/data/Dockerfiles/sogo/bootstrap-sogo.sh b/data/Dockerfiles/sogo/bootstrap-sogo.sh index 92acb591..77fad531 100755 --- a/data/Dockerfiles/sogo/bootstrap-sogo.sh +++ b/data/Dockerfiles/sogo/bootstrap-sogo.sh @@ -1,7 +1,7 @@ #!/bin/bash # Wait for MySQL to warm-up -while mysqladmin ping --host 172.22.1.250 --silent; do +while mysqladmin ping --host mysql -u${DBUSER} -p${DBPASS}${DBPASS} --silent; do # Wait until port becomes free and send sig until ! nc -z sogo-mailcow 20000; From 998523bdfa26eb654a75df629a3bc597a60f31d2 Mon Sep 17 00:00:00 2001 From: andryyy Date: Tue, 12 Sep 2017 20:57:54 +0200 Subject: [PATCH 2/6] [Web] Allow ratelimt per user, overrides domain tl --- data/web/edit.php | 26 +++++++++-- data/web/inc/functions.mailbox.inc.php | 65 +++++++++++++++++++------- data/web/json_api.php | 8 ++-- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/data/web/edit.php b/data/web/edit.php index 0e7460bc..4c60fadf 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -138,7 +138,7 @@ if (isset($_SESSION['mailcow_cc_role'])) { !empty($_GET["domain"])) { $domain = $_GET["domain"]; $result = mailbox('get', 'domain_details', $domain); - $rl = mailbox('get', 'domain_ratelimit', $domain); + $rl = mailbox('get', 'ratelimit', $domain); $rlyhosts = relayhost('get'); if (!empty($result)) { ?> @@ -251,7 +251,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +

@@ -314,7 +314,7 @@ if (isset($_SESSION['mailcow_cc_role'])) { !empty($_GET["aliasdomain"])) { $alias_domain = $_GET["aliasdomain"]; $result = mailbox('get', 'alias_domain_details', $alias_domain); - $rl = mailbox('get', 'domain_ratelimit', $alias_domain); + $rl = mailbox('get', 'ratelimit', $alias_domain); if (!empty($result)) { ?>

@@ -353,7 +353,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
- +

@@ -478,6 +479,23 @@ if (isset($_SESSION['mailcow_cc_role'])) { +
+
+
+ + +
+
+ +
+
+ +
+
sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) ); break; - case 'domain_ratelimit': + case 'ratelimit': $rl_value = intval($_data['rl_value']); $rl_frame = $_data['rl_frame']; if (!in_array($rl_frame, array('s', 'm', 'h'))) { @@ -1199,24 +1199,38 @@ function mailbox($_action, $_type, $_data = null) { ); return false; } - if (!is_array($_data['domain'])) { - $domains = array(); - $domains[] = $_data['domain']; + if (!is_array($_data['object'])) { + $objects = array(); + $objects[] = $_data['object']; } else { - $domains = $_data['domain']; + $objects = $_data['object']; } - foreach ($domains as $domain) { - if (!is_valid_domain_name($domain) || !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); + foreach ($objects as $object) { + if (is_valid_domain_name($object)) { + if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + } + elseif (filter_var($object, FILTER_VALIDATE_EMAIL)) { + if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + } + else { return false; } if (empty($rl_value)) { try { - $redis->hDel('RL_VALUE', $domain); + $redis->hDel('RL_VALUE', $object); } catch (RedisException $e) { $_SESSION['return'] = array( @@ -1228,7 +1242,7 @@ function mailbox($_action, $_type, $_data = null) { } else { try { - $redis->hSet('RL_VALUE', $domain, $rl_value . ' / 1' . $rl_frame); + $redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame); } catch (RedisException $e) { $_SESSION['return'] = array( @@ -1241,7 +1255,7 @@ function mailbox($_action, $_type, $_data = null) { } $_SESSION['return'] = array( 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_modified'], implode(', ', $domains)) + 'msg' => sprintf($lang['success']['domain_modified'], implode(', ', $objects)) ); break; case 'syncjob': @@ -2385,9 +2399,26 @@ function mailbox($_action, $_type, $_data = null) { } return $aliases; break; - case 'domain_ratelimit': - $aliases = array(); - if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { + case 'ratelimit': + if (is_valid_domain_name($_data)) { + if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + } + elseif (filter_var($_data, FILTER_VALIDATE_EMAIL)) { + if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + } + else { return false; } try { diff --git a/data/web/json_api.php b/data/web/json_api.php index b7acb724..ec7899c7 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -2133,13 +2133,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u )); } break; - case "domain-ratelimit": + case "ratelimit": if (isset($_POST['items']) && isset($_POST['attr'])) { $items = (array)json_decode($_POST['items'], true); $attr = (array)json_decode($_POST['attr'], true); - $postarray = array_merge(array('domain' => $items), $attr); - if (is_array($postarray['domain'])) { - if (mailbox('edit', 'domain_ratelimit', $postarray) === false) { + $postarray = array_merge(array('object' => $items), $attr); + if (is_array($postarray['object'])) { + if (mailbox('edit', 'ratelimit', $postarray) === false) { if (isset($_SESSION['return'])) { echo json_encode($_SESSION['return']); } From 79985ad7ed1131a6ffd2abc0122269dac8a1ce46 Mon Sep 17 00:00:00 2001 From: andryyy Date: Tue, 12 Sep 2017 20:59:24 +0200 Subject: [PATCH 3/6] [Compose] Disable strict mode in MariaDB 10.2 (temp.), skip most DNS resolving in MariaDB, fix MariaDB healthcheck by using a valid user, set larger MariaDB packet size --- docker-compose.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8704abb1..2bee1e40 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,10 +23,10 @@ services: - unbound mysql-mailcow: - image: mariadb:10.1 - command: mysqld --max_allowed_packet=128M --max-connections=1500 + image: mariadb:10.2 + command: mysqld --max_allowed_packet=192M --max-connections=1500 --innodb-strict-mode=0 --skip-host-cache --skip-name-resolve --log-warnings=0 healthcheck: - test: ["CMD", "mysqladmin", "ping", "--host", "localhost", "--silent"] + test: ["CMD", "mysqladmin", "-u$DBUSER", "-p$DBPASS", "ping", "-h", "localhost"] interval: 5s timeout: 5s retries: 10 @@ -108,7 +108,7 @@ services: - rspamd php-fpm-mailcow: - image: mailcow/phpfpm:1.0 + image: mailcow/phpfpm:1.1 build: ./data/Dockerfiles/phpfpm command: "php-fpm -d date.timezone=${TZ}" depends_on: @@ -140,7 +140,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.7 + image: mailcow/sogo:1.8 build: ./data/Dockerfiles/sogo depends_on: unbound-mailcow: From 71070fbe863bcc5a5bb89aa1b968ac86901d7103 Mon Sep 17 00:00:00 2001 From: andryyy Date: Tue, 12 Sep 2017 22:48:12 +0200 Subject: [PATCH 4/6] [Web] Fix admin injection query --- data/web/inc/init_db.inc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index f63a42d8..9fe50fe7 100644 --- a/data/web/inc/init_db.inc.php +++ b/data/web/inc/init_db.inc.php @@ -3,7 +3,7 @@ function init_db_schema() { try { global $pdo; - $db_version = "31082017_0853"; + $db_version = "12092017_2254"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -649,7 +649,7 @@ function init_db_schema() { // 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 + SELECT 'admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1 FROM `admin` WHERE NOT EXISTS (SELECT * FROM `admin`);"); $stmt = $pdo->query("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) SELECT `username`, 'ALL', NOW(), 1 FROM `admin` From 344f88dbf35bda8961743c27415779c29115bbfb Mon Sep 17 00:00:00 2001 From: andryyy Date: Wed, 13 Sep 2017 19:25:54 +0200 Subject: [PATCH 5/6] [Update] Set merge.defaultToUpstream true --- update.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/update.sh b/update.sh index 62b23d10..af4fa1a7 100755 --- a/update.sh +++ b/update.sh @@ -74,7 +74,7 @@ else exit 1 fi -read -r -p "Are you sure you want to update mailcow: dockerized? All containers will be stopped. [y/N] " response +read -r -p "Are you sure you want to update mailcow: dockerized? [y/N] " response if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then echo "OK, exiting." exit 0 @@ -92,6 +92,7 @@ git commit -am "Before update on ${DATE}" > /dev/null echo -e "\e[32mFetching updated code from remote...\e[0m" git fetch origin ${BRANCH} echo -e "\e[32mMerging local with remote code (recursive, options: \"theirs\", \"patience\"...\e[0m" +git config merge.defaultToUpstream true git merge -Xtheirs -Xpatience -m "After update on ${DATE}" # Need to use a variable to not pass return codes of if checks MERGE_RETURN=$? From 00e465a9a1cbbef2d2d271ee8cd7a7b5c896d062 Mon Sep 17 00:00:00 2001 From: andryyy Date: Thu, 14 Sep 2017 13:32:11 +0200 Subject: [PATCH 6/6] [Dovecot] Allow INBOX to be shared, sigh... fixes #594 --- data/conf/dovecot/dovecot.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index e478f0b2..59362958 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -23,6 +23,7 @@ ssl_dh_parameters_length = 2048 log_timestamp = "%Y-%m-%d %H:%M:%S " recipient_delimiter = + auth_master_user_separator = * +mail_shared_explicit_inbox = yes mail_prefetch_count = 30 passdb { driver = passwd-file