diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 9f8f5313..469edacc 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -82,7 +82,7 @@ cat < /usr/local/etc/dovecot/sql/dovecot-dict-sql-passdb.conf driver = mysql connect = "host=mysql dbname=${DBNAME} user=${DBUSER} password=${DBPASS}" default_pass_scheme = SSHA256 -password_query = SELECT password FROM mailbox WHERE username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') +password_query = SELECT password FROM mailbox WHERE username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') AND JSON_EXTRACT(attributes, "$.force_pw_update") != 1 user_query = SELECT CONCAT('maildir:/var/vmail/',maildir) AS mail, 5000 AS uid, 5000 AS gid, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1' iterate_query = SELECT username FROM mailbox WHERE active='1'; EOF diff --git a/data/Dockerfiles/dovecot/imapsync_cron.pl b/data/Dockerfiles/dovecot/imapsync_cron.pl index 8afc3b20..47f9bbf7 100755 --- a/data/Dockerfiles/dovecot/imapsync_cron.pl +++ b/data/Dockerfiles/dovecot/imapsync_cron.pl @@ -74,6 +74,14 @@ while ($row = $sth->fetchrow_arrayref()) { "--timeout1", "10", "--tmpdir", "/tmp", "--subscribeall", + "--nofoldersizes", + "--skipsize", + "--buffersize 8192000", + "--skipheader 'X-*'", + "--split1 3000", + "--split2 3000", + "--fastio1", + "--fastio2", ($exclude eq "" ? () : ("--exclude", $exclude)), ($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)), ($maxage eq "0" ? () : ('--maxage', $maxage)), diff --git a/data/Dockerfiles/sogo/bootstrap-sogo.sh b/data/Dockerfiles/sogo/bootstrap-sogo.sh index c360e30e..07365981 100755 --- a/data/Dockerfiles/sogo/bootstrap-sogo.sh +++ b/data/Dockerfiles/sogo/bootstrap-sogo.sh @@ -19,14 +19,13 @@ mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP VIEW IF EXISTS so mysql --host mysql -u ${DBUSER} -p${DBPASS} ${DBNAME} << EOF CREATE VIEW sogo_view (c_uid, domain, c_name, c_password, c_cn, mail, aliases, ad_aliases, home, kind, multiple_bookings) AS -SELECT mailbox.username, mailbox.domain, mailbox.username, mailbox.password, mailbox.name, mailbox.username, IFNULL(GROUP_CONCAT(ga.aliases SEPARATOR ' '), ''), IFNULL(gda.ad_alias, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox +SELECT mailbox.username, mailbox.domain, mailbox.username, if(json_extract(attributes, '$.force_pw_update') = '0', password, 'invalid'), mailbox.name, mailbox.username, IFNULL(GROUP_CONCAT(ga.aliases SEPARATOR ' '), ''), IFNULL(gda.ad_alias, ''), CONCAT('/var/vmail/', maildir), mailbox.kind, mailbox.multiple_bookings FROM mailbox LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)') LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username WHERE mailbox.active = '1' GROUP BY mailbox.username; EOF - mkdir -p /var/lib/sogo/GNUstep/Defaults/ # Generate plist header with timezone data diff --git a/data/web/edit.php b/data/web/edit.php index 6652d7f3..b2f6c27e 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -390,6 +390,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
@@ -476,6 +477,14 @@ if (isset($_SESSION['mailcow_cc_role'])) {
+
+
+
+ + +
+
+
diff --git a/data/web/inc/ajax/destroy_tfa_auth.php b/data/web/inc/ajax/destroy_tfa_auth.php new file mode 100644 index 00000000..72c7f1e3 --- /dev/null +++ b/data/web/inc/ajax/destroy_tfa_auth.php @@ -0,0 +1,6 @@ + diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php index d0932514..1015c114 100644 --- a/data/web/inc/footer.inc.php +++ b/data/web/inc/footer.inc.php @@ -79,6 +79,17 @@ $(document).ready(function() { }); } }); + $('#ConfirmTFAModal').on('hidden.bs.modal', function(){ + $.ajax({ + type: "GET", + cache: false, + dataType: 'script', + url: '/inc/ajax/destroy_tfa_auth.php', + complete: function(data){ + window.location = window.location.href.split("#")[0]; + } + }); + }); // Set TFA modals @@ -205,7 +216,7 @@ $(document).ready(function() { $('#triggerRestartContainer').html(' '); $('#statusTriggerRestartContainer2').append(data); $('#triggerRestartContainer').html(' '); - location.reload(); + window.location = window.location.href.split("#")[0]; } }); }); diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 92f4da2b..6876c0d2 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -415,7 +415,7 @@ function edit_user_account($postarray) { } $password_hashed = hash_password($password_new); try { - $stmt = $pdo->prepare("UPDATE `mailbox` SET `password` = :password_hashed WHERE `username` = :username"); + $stmt = $pdo->prepare("UPDATE `mailbox` SET `password` = :password_hashed, `attributes` = JSON_SET(`attributes`, '$.force_pw_update', '0') WHERE `username` = :username"); $stmt->execute(array( ':password_hashed' => $password_hashed, ':username' => $username diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 6cc5bf30..c6f3cff2 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -1954,6 +1954,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $is_now = mailbox('get', 'mailbox_details', $username); if (!empty($is_now)) { $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + (int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']); $name = (!empty($_data['name'])) ? $_data['name'] : $is_now['name']; $domain = $is_now['domain']; $quota_m = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['quota'] / 1048576); @@ -2113,24 +2114,11 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { } $password_hashed = hash_password($password); try { - $stmt = $pdo->prepare("UPDATE `alias` SET - `active` = :active - WHERE `address` = :address"); - $stmt->execute(array( - ':address' => $username, - ':active' => $active - )); $stmt = $pdo->prepare("UPDATE `mailbox` SET - `active` = :active, `password` = :password_hashed, - `name`= :name, - `quota` = :quota_b WHERE `username` = :username"); $stmt->execute(array( ':password_hashed' => $password_hashed, - ':active' => $active, - ':name' => $name, - ':quota_b' => $quota_b, ':username' => $username )); } @@ -2153,12 +2141,14 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $stmt = $pdo->prepare("UPDATE `mailbox` SET `active` = :active, `name`= :name, - `quota` = :quota_b + `quota` = :quota_b, + `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update) WHERE `username` = :username"); $stmt->execute(array( ':active' => $active, ':name' => $name, ':quota_b' => $quota_b, + ':force_pw_update' => $force_pw_update, ':username' => $username )); } @@ -3070,6 +3060,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { `mailbox`.`domain`, `mailbox`.`quota`, `quota2`.`bytes`, + `attributes`, `quota2`.`messages` FROM `mailbox`, `quota2`, `domain` WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' AND `mailbox`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox"); @@ -3097,6 +3088,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) { $mailboxdata['active_int'] = $row['active_int']; $mailboxdata['domain'] = $row['domain']; $mailboxdata['quota'] = $row['quota']; + $mailboxdata['attributes'] = json_decode($row['attributes'], true); $mailboxdata['quota_used'] = intval($row['bytes']); $mailboxdata['percent_in_use'] = round((intval($row['bytes']) / intval($row['quota'])) * 100); $mailboxdata['messages'] = $row['messages']; diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php index e11729fb..ef07d51f 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 = "08022018_2019"; + $db_version = "16022018_1419"; $stmt = $pdo->query("SHOW TABLES LIKE 'versions'"); $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); @@ -187,6 +187,7 @@ function init_db_schema() { "domain" => "VARCHAR(255) NOT NULL", "tls_enforce_in" => "TINYINT(1) NOT NULL DEFAULT '0'", "tls_enforce_out" => "TINYINT(1) NOT NULL DEFAULT '0'", + "attributes" => "JSON DEFAULT '{}'", "kind" => "VARCHAR(100) NOT NULL DEFAULT ''", "multiple_bookings" => "TINYINT(1) NOT NULL DEFAULT '0'", "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)", diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php index cd3a5ec1..f47534c2 100644 --- a/data/web/lang/lang.de.php +++ b/data/web/lang/lang.de.php @@ -85,6 +85,7 @@ $lang['danger']['sender_acl_invalid'] = 'Sender ACL Wert muss eine Adresse oder $lang['danger']['domain_not_empty'] = 'Kann nur leere Domains entfernen'; $lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an'; $lang['user']['loading'] = "Lade..."; +$lang['user']['force_pw_update'] = 'Das Passwort für diesen Benutzer muss geändert werden, damit die Zugriffssperre auf die Groupwarekomponenten wieder freigeschaltet wird.'; $lang['user']['active_sieve'] = "Aktiver Filter"; $lang['user']['show_sieve_filters'] = "Zeige aktiven Filter des Benutzers"; $lang['user']['no_active_filter'] = "Kein aktiver Filter vorhanden"; @@ -250,6 +251,8 @@ $lang['edit']['max_mailboxes'] = 'Max. Mailboxanzahl:'; $lang['edit']['title'] = 'Objekt bearbeiten'; $lang['edit']['target_address'] = 'Ziel-Adresse(n) (getrennt durch Komma):'; $lang['edit']['active'] = 'Aktiv'; +$lang['edit']['force_pw_update'] = 'Erzwinge Passwortänderung bei nächstem Login'; +$lang['edit']['force_pw_update_info'] = 'Dem Benutzer wird lediglich der Zugang zur mailcow UI ermöglicht.'; $lang['edit']['target_domain'] = 'Ziel-Domain:'; $lang['edit']['password'] = 'Passwort:'; $lang['edit']['password_repeat'] = 'Passwort (Wiederholung):'; diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php index d02f2d74..a9145f30 100644 --- a/data/web/lang/lang.en.php +++ b/data/web/lang/lang.en.php @@ -84,6 +84,7 @@ $lang['danger']['sender_acl_invalid'] = "Sender ACL value is invalid"; $lang['danger']['domain_not_empty'] = "Cannot remove non-empty domain"; $lang['danger']['validity_missing'] = 'Please assign a period of validity'; $lang['user']['loading'] = "Loading..."; +$lang['user']['force_pw_update'] = 'You must set a new password to be able to access groupware related services.'; $lang['user']['active_sieve'] = "Active filter"; $lang['user']['show_sieve_filters'] = "Show active user sieve filter"; $lang['user']['no_active_filter'] = "No active filter available"; @@ -249,6 +250,8 @@ $lang['edit']['max_mailboxes'] = 'Max. possible mailboxes'; $lang['edit']['title'] = 'Edit object'; $lang['edit']['target_address'] = 'Goto address/es (comma-separated)'; $lang['edit']['active'] = 'Active'; +$lang['edit']['force_pw_update'] = 'Force password update at next login'; +$lang['edit']['force_pw_update_info'] = 'This user will only be able to login to mailcow UI.'; $lang['edit']['target_domain'] = 'Target domain'; $lang['edit']['password'] = 'Password'; $lang['edit']['password_repeat'] = 'Confirmation password (repeat)'; diff --git a/data/web/user.php b/data/web/user.php index 6b807945..a7b06806 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -89,6 +89,9 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
+ +
+

[]

[]

diff --git a/docker-compose.yml b/docker-compose.yml index 6252727d..e2612adc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -142,7 +142,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.16 + image: mailcow/sogo:1.17 build: ./data/Dockerfiles/sogo environment: - DBNAME=${DBNAME} @@ -165,7 +165,11 @@ services: - sogo dovecot-mailcow: +<<<<<<< HEAD image: mailcow/dovecot:1.21 +======= + image: mailcow/dovecot:1.22 +>>>>>>> master build: ./data/Dockerfiles/dovecot cap_add: - NET_BIND_SERVICE