blob: ffce9f44cbcb7ff15ba5a36fad76a31e9097c509 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2function acl($_action, $_scope = null, $_data = null) {
3 global $pdo;
4 global $lang;
5 $_data_log = $_data;
6 switch ($_action) {
7 case 'edit':
8 switch ($_scope) {
9 case 'user':
10 if (!is_array($_data['username'])) {
11 $usernames = array();
12 $usernames[] = $_data['username'];
13 }
14 else {
15 $usernames = $_data['username'];
16 }
17 foreach ($usernames as $username) {
18 // Cast to array for single selections
19 $acls = (array)$_data['user_acl'];
20 // Create associative array from index array
21 // All set items are given 1 as value
22 foreach ($acls as $acl_key => $acl_val) {
23 $acl_post[$acl_val] = 1;
24 }
25 // Users cannot change their own ACL
26 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)
27 || ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
28 $_SESSION['return'][] = array(
29 'type' => 'danger',
30 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
31 'msg' => 'access_denied'
32 );
33 continue;
34 }
35 // Read all available acl options by calling acl(get)
36 // Set all available acl options we cannot find in the post data to 0, else 1
37 $is_now = acl('get', 'user', $username);
38 if (!empty($is_now)) {
39 foreach ($is_now as $acl_now_name => $acl_now_val) {
40 $set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
41 }
42 }
43 else {
44 $_SESSION['return'][] = array(
45 'type' => 'danger',
46 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
47 'msg' => 'Cannot determine current ACL'
48 );
49 continue;
50 }
51 foreach ($set_acls as $set_acl_key => $set_acl_val) {
52 $stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
53 WHERE `username` = :username");
54 $stmt->execute(array(
55 ':username' => $username,
56 ));
57 }
58 $_SESSION['return'][] = array(
59 'type' => 'success',
60 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
61 'msg' => array('acl_saved', $username)
62 );
63 }
64 break;
65 case 'domainadmin':
66 if ($_SESSION['mailcow_cc_role'] != 'admin') {
67 $_SESSION['return'][] = array(
68 'type' => 'danger',
69 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
70 'msg' => 'access_denied'
71 );
72 return false;
73 }
74 if (!is_array($_data['username'])) {
75 $usernames = array();
76 $usernames[] = $_data['username'];
77 }
78 else {
79 $usernames = $_data['username'];
80 }
81 foreach ($usernames as $username) {
82 // Cast to array for single selections
83 $acls = (array)$_data['da_acl'];
84 // Create associative array from index array
85 // All set items are given 1 as value
86 foreach ($acls as $acl_key => $acl_val) {
87 $acl_post[$acl_val] = 1;
88 }
89 // Users cannot change their own ACL
90 if ($_SESSION['mailcow_cc_role'] != 'admin') {
91 $_SESSION['return'][] = array(
92 'type' => 'danger',
93 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
94 'msg' => 'access_denied'
95 );
96 continue;
97 }
98 // Read all available acl options by calling acl(get)
99 // Set all available acl options we cannot find in the post data to 0, else 1
100 $is_now = acl('get', 'domainadmin', $username);
101 if (!empty($is_now)) {
102 foreach ($is_now as $acl_now_name => $acl_now_val) {
103 $set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
104 }
105 }
106 else {
107 $_SESSION['return'][] = array(
108 'type' => 'danger',
109 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
110 'msg' => 'Cannot determine current ACL'
111 );
112 continue;
113 }
114 foreach ($set_acls as $set_acl_key => $set_acl_val) {
115 $stmt = $pdo->prepare("UPDATE `da_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
116 WHERE `username` = :username");
117 $stmt->execute(array(
118 ':username' => $username,
119 ));
120 }
121 $_SESSION['return'][] = array(
122 'type' => 'success',
123 'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
124 'msg' => array('acl_saved', $username)
125 );
126 }
127 break;
128 }
129 break;
130 case 'get':
131 switch ($_scope) {
132 case 'user':
133 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
134 return false;
135 }
136 $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
137 $stmt->execute(array(':username' => $_data));
138 $data = $stmt->fetch(PDO::FETCH_ASSOC);
139 if ($_SESSION['mailcow_cc_role'] == 'domainadmin') {
140 // Domain admins cannot see, add or remove user ACLs they don't have access to by themselves
141 // Editing a user will use acl("get", "user") to determine granted ACLs and therefore block unallowed access escalation via form editing
142 $self_da_acl = acl('get', 'domainadmin', $_SESSION['mailcow_cc_username']);
143 foreach ($self_da_acl as $self_da_acl_key => $self_da_acl_val) {
144 if ($self_da_acl_val == 0) {
145 unset($data[$self_da_acl_key]);
146 }
147 }
148 }
149 if (!empty($data)) {
150 unset($data['username']);
151 return $data;
152 }
153 else {
154 return false;
155 }
156 break;
157 case 'domainadmin':
158 if ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin') {
159 return false;
160 }
161 if ($_SESSION['mailcow_cc_role'] == 'domainadmin' && $_SESSION['mailcow_cc_username'] != $_data) {
162 return false;
163 }
164 $stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
165 $stmt->execute(array(':username' => $_data));
166 $data = $stmt->fetch(PDO::FETCH_ASSOC);
167 if (!empty($data)) {
168 unset($data['username']);
169 return $data;
170 }
171 else {
172 return false;
173 }
174 break;
175 }
176 break;
177 case 'to_session':
178 if (!isset($_SESSION['mailcow_cc_role'])) {
179 return false;
180 }
181 unset($_SESSION['acl']);
182 $username = strtolower(trim($_SESSION['mailcow_cc_username']));
183 // Admins get access to all modules
184 if ($_SESSION['mailcow_cc_role'] == 'admin' ||
185 (isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'admin')) {
186 $stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
187 $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
188 while ($row = array_shift($acl_all)) {
189 $acl['acl'][$row['Field']] = 1;
190 }
191 $stmt = $pdo->query("SHOW COLUMNS FROM `da_acl` WHERE `Field` != 'username';");
192 $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
193 while ($row = array_shift($acl_all)) {
194 $acl['acl'][$row['Field']] = 1;
195 }
196 }
197 elseif ($_SESSION['mailcow_cc_role'] == 'domainadmin' ||
198 (isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'domainadmin')) {
199 // Read all exting user_acl modules and set to 1
200 $stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
201 $acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
202 while ($row = array_shift($acl_all)) {
203 $acl['acl'][$row['Field']] = 1;
204 }
205 // Read da_acl rules for current user, OVERWRITE overlapping modules
206 // This prevents access to a users sync jobs, when a domain admins was not given access to sync jobs
207 $stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
208 $stmt->execute(array(':username' => (isset($_SESSION["dual-login"]["username"])) ? $_SESSION["dual-login"]["username"] : $username));
209 $acl_user = $stmt->fetch(PDO::FETCH_ASSOC);
210 foreach ($acl_user as $acl_user_key => $acl_user_val) {
211 $acl['acl'][$acl_user_key] = $acl_user_val;
212 }
213 unset($acl['acl']['username']);
214 }
215 elseif ($_SESSION['mailcow_cc_role'] == 'user') {
216 $stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
217 $stmt->execute(array(':username' => $username));
218 $acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
219 unset($acl['acl']['username']);
220 }
221 if (!empty($acl)) {
222 $_SESSION = array_merge($_SESSION, $acl);
223 }
224 break;
225 }
226}