mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2024-12-15 09:00:26 +08:00
ecebfe15df
[Web] Disallow a domain admin to set intersecting user ACLs [Web] Allow Pushover and SOGo EAS cache reset by default, disallow profile reset by default
226 lines
9.5 KiB
PHP
226 lines
9.5 KiB
PHP
<?php
|
|
function acl($_action, $_scope = null, $_data = null) {
|
|
global $pdo;
|
|
global $lang;
|
|
$_data_log = $_data;
|
|
switch ($_action) {
|
|
case 'edit':
|
|
switch ($_scope) {
|
|
case 'user':
|
|
if (!is_array($_data['username'])) {
|
|
$usernames = array();
|
|
$usernames[] = $_data['username'];
|
|
}
|
|
else {
|
|
$usernames = $_data['username'];
|
|
}
|
|
foreach ($usernames as $username) {
|
|
// Cast to array for single selections
|
|
$acls = (array)$_data['user_acl'];
|
|
// Create associative array from index array
|
|
// All set items are given 1 as value
|
|
foreach ($acls as $acl_key => $acl_val) {
|
|
$acl_post[$acl_val] = 1;
|
|
}
|
|
// Users cannot change their own ACL
|
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)
|
|
|| ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'danger',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => 'access_denied'
|
|
);
|
|
continue;
|
|
}
|
|
// Read all available acl options by calling acl(get)
|
|
// Set all available acl options we cannot find in the post data to 0, else 1
|
|
$is_now = acl('get', 'user', $username);
|
|
if (!empty($is_now)) {
|
|
foreach ($is_now as $acl_now_name => $acl_now_val) {
|
|
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
|
|
}
|
|
}
|
|
else {
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'danger',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => 'Cannot determine current ACL'
|
|
);
|
|
continue;
|
|
}
|
|
foreach ($set_acls as $set_acl_key => $set_acl_val) {
|
|
$stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
|
|
WHERE `username` = :username");
|
|
$stmt->execute(array(
|
|
':username' => $username,
|
|
));
|
|
}
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'success',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => array('acl_saved', $username)
|
|
);
|
|
}
|
|
break;
|
|
case 'domainadmin':
|
|
if ($_SESSION['mailcow_cc_role'] != 'admin') {
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'danger',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => 'access_denied'
|
|
);
|
|
return false;
|
|
}
|
|
if (!is_array($_data['username'])) {
|
|
$usernames = array();
|
|
$usernames[] = $_data['username'];
|
|
}
|
|
else {
|
|
$usernames = $_data['username'];
|
|
}
|
|
foreach ($usernames as $username) {
|
|
// Cast to array for single selections
|
|
$acls = (array)$_data['da_acl'];
|
|
// Create associative array from index array
|
|
// All set items are given 1 as value
|
|
foreach ($acls as $acl_key => $acl_val) {
|
|
$acl_post[$acl_val] = 1;
|
|
}
|
|
// Users cannot change their own ACL
|
|
if ($_SESSION['mailcow_cc_role'] != 'admin') {
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'danger',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => 'access_denied'
|
|
);
|
|
continue;
|
|
}
|
|
// Read all available acl options by calling acl(get)
|
|
// Set all available acl options we cannot find in the post data to 0, else 1
|
|
$is_now = acl('get', 'domainadmin', $username);
|
|
if (!empty($is_now)) {
|
|
foreach ($is_now as $acl_now_name => $acl_now_val) {
|
|
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
|
|
}
|
|
}
|
|
else {
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'danger',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => 'Cannot determine current ACL'
|
|
);
|
|
continue;
|
|
}
|
|
foreach ($set_acls as $set_acl_key => $set_acl_val) {
|
|
$stmt = $pdo->prepare("UPDATE `da_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
|
|
WHERE `username` = :username");
|
|
$stmt->execute(array(
|
|
':username' => $username,
|
|
));
|
|
}
|
|
$_SESSION['return'][] = array(
|
|
'type' => 'success',
|
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
|
'msg' => array('acl_saved', $username)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'get':
|
|
switch ($_scope) {
|
|
case 'user':
|
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
|
return false;
|
|
}
|
|
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
|
$stmt->execute(array(':username' => $_data));
|
|
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if ($_SESSION['mailcow_cc_role'] == 'domainadmin') {
|
|
// Domain admins cannot see, add or remove user ACLs they don't have access to by themselves
|
|
// Editing a user will use acl("get", "user") to determine granted ACLs and therefore block unallowed access escalation via form editing
|
|
$self_da_acl = acl('get', 'domainadmin', $_SESSION['mailcow_cc_username']);
|
|
foreach ($self_da_acl as $self_da_acl_key => $self_da_acl_val) {
|
|
if ($self_da_acl_val == 0) {
|
|
unset($data[$self_da_acl_key]);
|
|
}
|
|
}
|
|
}
|
|
if (!empty($data)) {
|
|
unset($data['username']);
|
|
return $data;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
break;
|
|
case 'domainadmin':
|
|
if ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin') {
|
|
return false;
|
|
}
|
|
if ($_SESSION['mailcow_cc_role'] == 'domainadmin' && $_SESSION['mailcow_cc_username'] != $_data) {
|
|
return false;
|
|
}
|
|
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
|
|
$stmt->execute(array(':username' => $_data));
|
|
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
if (!empty($data)) {
|
|
unset($data['username']);
|
|
return $data;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 'to_session':
|
|
if (!isset($_SESSION['mailcow_cc_role'])) {
|
|
return false;
|
|
}
|
|
unset($_SESSION['acl']);
|
|
$username = strtolower(trim($_SESSION['mailcow_cc_username']));
|
|
// Admins get access to all modules
|
|
if ($_SESSION['mailcow_cc_role'] == 'admin' ||
|
|
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'admin')) {
|
|
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
|
|
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
while ($row = array_shift($acl_all)) {
|
|
$acl['acl'][$row['Field']] = 1;
|
|
}
|
|
$stmt = $pdo->query("SHOW COLUMNS FROM `da_acl` WHERE `Field` != 'username';");
|
|
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
while ($row = array_shift($acl_all)) {
|
|
$acl['acl'][$row['Field']] = 1;
|
|
}
|
|
}
|
|
elseif ($_SESSION['mailcow_cc_role'] == 'domainadmin' ||
|
|
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'domainadmin')) {
|
|
// Read all exting user_acl modules and set to 1
|
|
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
|
|
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
while ($row = array_shift($acl_all)) {
|
|
$acl['acl'][$row['Field']] = 1;
|
|
}
|
|
// Read da_acl rules for current user, OVERWRITE overlapping modules
|
|
// This prevents access to a users sync jobs, when a domain admins was not given access to sync jobs
|
|
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
|
|
$stmt->execute(array(':username' => (isset($_SESSION["dual-login"]["username"])) ? $_SESSION["dual-login"]["username"] : $username));
|
|
$acl_user = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
foreach ($acl_user as $acl_user_key => $acl_user_val) {
|
|
$acl['acl'][$acl_user_key] = $acl_user_val;
|
|
}
|
|
unset($acl['acl']['username']);
|
|
}
|
|
elseif ($_SESSION['mailcow_cc_role'] == 'user') {
|
|
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
|
$stmt->execute(array(':username' => $username));
|
|
$acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
unset($acl['acl']['username']);
|
|
}
|
|
if (!empty($acl)) {
|
|
$_SESSION = array_merge($_SESSION, $acl);
|
|
}
|
|
break;
|
|
}
|
|
} |