git subrepo commit (merge) mailcow/src/mailcow-dockerized
subrepo:
subdir: "mailcow/src/mailcow-dockerized"
merged: "81fb18894"
upstream:
origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "4ca02ecee"
git-subrepo:
version: "0.4.6"
origin: "???"
commit: "???"
Update to upstream 2026-10. Local patches re-applied by hand
(no Unbound DNS for containers, IPv6 off by default, fake-MySQL
stubs in dockerapi, Postfix overrides, no .env symlink); dropped
the unused dovecot and clamd Dockerfile patches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I2c2c194d1d436b841358685f5f94aef09eb19ae8
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/functions.admin.inc.php b/mailcow/src/mailcow-dockerized/data/web/inc/functions.admin.inc.php
index 9f42fd7..7bd0af4 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/functions.admin.inc.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/functions.admin.inc.php
@@ -121,34 +121,56 @@
continue;
}
}
- if (!empty($password)) {
- if (password_check($password, $password2) !== true) {
- return false;
+ // Check if this is a self password change via forced update
+ if ($username == $_SESSION['mailcow_cc_username'] && !empty($_SESSION['pending_pw_update'])) {
+ // Forced password update: only change password and clear force_pw_update flag
+ if (!empty($password)) {
+ if (password_check($password, $_data['password2']) !== true) {
+ return false;
+ }
+ $password_hashed = hash_password($password);
+ $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed,
+ `attributes` = JSON_SET(COALESCE(`attributes`, '{}'), '$.force_pw_update', '0')
+ WHERE `username` = :username");
+ $stmt->execute(array(
+ ':password_hashed' => $password_hashed,
+ ':username' => $username
+ ));
+ unset($_SESSION['pending_pw_update']);
}
- $password_hashed = hash_password($password);
- $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
- $stmt->execute(array(
- ':password_hashed' => $password_hashed,
- ':username_new' => $username_new,
- ':username' => $username,
- ':active' => $active
- ));
- if (isset($_data['disable_tfa'])) {
- $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
- $stmt->execute(array(':username' => $username));
+ } else {
+ // Normal admin edit: update all attributes
+ $force_tfa = intval($_data['force_tfa'] ?? 0) ? 1 : 0;
+ $force_pw_update = intval($_data['force_pw_update'] ?? 0) ? 1 : 0;
+ if (!empty($password)) {
+ if (password_check($password, $password2) !== true) {
+ return false;
+ }
+ $password_hashed = hash_password($password);
+ $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed,
+ `attributes` = JSON_SET(COALESCE(`attributes`, '{}'), '$.force_tfa', :force_tfa, '$.force_pw_update', :force_pw_update)
+ WHERE `username` = :username");
+ $stmt->execute(array(
+ ':password_hashed' => $password_hashed,
+ ':username_new' => $username_new,
+ ':username' => $username,
+ ':active' => $active,
+ ':force_tfa' => strval($force_tfa),
+ ':force_pw_update' => strval($force_pw_update)
+ ));
}
else {
- $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
- $stmt->execute(array(':username_new' => $username_new, ':username' => $username));
+ $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active,
+ `attributes` = JSON_SET(COALESCE(`attributes`, '{}'), '$.force_tfa', :force_tfa, '$.force_pw_update', :force_pw_update)
+ WHERE `username` = :username");
+ $stmt->execute(array(
+ ':username_new' => $username_new,
+ ':username' => $username,
+ ':active' => $active,
+ ':force_tfa' => strval($force_tfa),
+ ':force_pw_update' => strval($force_pw_update)
+ ));
}
- }
- else {
- $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username");
- $stmt->execute(array(
- ':username_new' => $username_new,
- ':username' => $username,
- ':active' => $active
- ));
if (isset($_data['disable_tfa'])) {
$stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
$stmt->execute(array(':username' => $username));
@@ -223,7 +245,8 @@
`tfa`.`active` AS `tfa_active`,
`admin`.`username`,
`admin`.`created`,
- `admin`.`active` AS `active`
+ `admin`.`active` AS `active`,
+ `admin`.`attributes` AS `attributes`
FROM `admin`
LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`admin`.`username`
WHERE `admin`.`username`= :admin AND `superadmin` = '1'");
@@ -240,6 +263,7 @@
$admindata['active'] = $row['active'];
$admindata['active_int'] = $row['active'];
$admindata['created'] = $row['created'];
+ $admindata['attributes'] = json_decode($row['attributes'], true) ?? array('force_tfa' => '0', 'force_pw_update' => '0');
return $admindata;
break;
}