git subrepo clone https://github.com/mailcow/mailcow-dockerized.git mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "a832becb"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "a832becb"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: If5be2d621a211e164c9b6577adaa7884449f16b5
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/functions.acl.inc.php b/mailcow/src/mailcow-dockerized/data/web/inc/functions.acl.inc.php
new file mode 100644
index 0000000..ffce9f4
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/functions.acl.inc.php
@@ -0,0 +1,226 @@
+<?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;
+ }
+}
\ No newline at end of file