blob: 206b3715f1c424b6111fee056a6dbe7d4f8e6475 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2function domain_admin($_action, $_data = null) {
3 global $pdo;
4 global $lang;
5 $_data_log = $_data;
6 !isset($_data_log['password']) ?: $_data_log['password'] = '*';
7 !isset($_data_log['password2']) ?: $_data_log['password2'] = '*';
8 !isset($_data_log['user_old_pass']) ?: $_data_log['user_old_pass'] = '*';
9 !isset($_data_log['user_new_pass']) ?: $_data_log['user_new_pass'] = '*';
10 !isset($_data_log['user_new_pass2']) ?: $_data_log['user_new_pass2'] = '*';
11 switch ($_action) {
12 case 'add':
13 $username = strtolower(trim($_data['username']));
14 $password = $_data['password'];
15 $password2 = $_data['password2'];
16 $domains = (array)$_data['domains'];
17 $active = intval($_data['active']);
18 if ($_SESSION['mailcow_cc_role'] != "admin") {
19 $_SESSION['return'][] = array(
20 'type' => 'danger',
21 'log' => array(__FUNCTION__, $_action, $_data_log),
22 'msg' => 'access_denied'
23 );
24 return false;
25 }
26 if (empty($domains)) {
27 $_SESSION['return'][] = array(
28 'type' => 'danger',
29 'log' => array(__FUNCTION__, $_action, $_data_log),
30 'msg' => 'domain_invalid'
31 );
32 return false;
33 }
34 if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username) || $username == 'API') {
35 $_SESSION['return'][] = array(
36 'type' => 'danger',
37 'log' => array(__FUNCTION__, $_action, $_data_log),
38 'msg' => array('username_invalid', $username)
39 );
40 return false;
41 }
42
43 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
44 WHERE `username` = :username");
45 $stmt->execute(array(':username' => $username));
46 $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC));
47
48 $stmt = $pdo->prepare("SELECT `username` FROM `admin`
49 WHERE `username` = :username");
50 $stmt->execute(array(':username' => $username));
51 $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC));
52
53 $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins`
54 WHERE `username` = :username");
55 $stmt->execute(array(':username' => $username));
56 $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC));
57
58 foreach ($num_results as $num_results_each) {
59 if ($num_results_each != 0) {
60 $_SESSION['return'][] = array(
61 'type' => 'danger',
62 'log' => array(__FUNCTION__, $_action, $_data_log),
63 'msg' => array('object_exists', htmlspecialchars($username))
64 );
65 return false;
66 }
67 }
68 if (!empty($password) && !empty($password2)) {
69 if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
70 $_SESSION['return'][] = array(
71 'type' => 'danger',
72 'log' => array(__FUNCTION__, $_action, $_data_log),
73 'msg' => 'password_complexity'
74 );
75 return false;
76 }
77 if ($password != $password2) {
78 $_SESSION['return'][] = array(
79 'type' => 'danger',
80 'log' => array(__FUNCTION__, $_action, $_data_log),
81 'msg' => 'password_mismatch'
82 );
83 return false;
84 }
85 $password_hashed = hash_password($password);
86 $valid_domains = 0;
87 foreach ($domains as $domain) {
88 if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
89 $_SESSION['return'][] = array(
90 'type' => 'danger',
91 'log' => array(__FUNCTION__, $_action, $_data_log),
92 'msg' => array('domain_invalid', htmlspecialchars($domain))
93 );
94 continue;
95 }
96 $valid_domains++;
97 $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
98 VALUES (:username, :domain, :created, :active)");
99 $stmt->execute(array(
100 ':username' => $username,
101 ':domain' => $domain,
102 ':created' => date('Y-m-d H:i:s'),
103 ':active' => $active
104 ));
105 }
106 if ($valid_domains != 0) {
107 $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
108 VALUES (:username, :password_hashed, '0', :active)");
109 $stmt->execute(array(
110 ':username' => $username,
111 ':password_hashed' => $password_hashed,
112 ':active' => $active
113 ));
114 }
115 }
116 else {
117 $_SESSION['return'][] = array(
118 'type' => 'danger',
119 'log' => array(__FUNCTION__, $_action, $_data_log),
120 'msg' => 'password_empty'
121 );
122 return false;
123 }
124 $stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)");
125 $stmt->execute(array(
126 ':username' => $username
127 ));
128 $_SESSION['return'][] = array(
129 'type' => 'success',
130 'log' => array(__FUNCTION__, $_action, $_data_log),
131 'msg' => array('domain_admin_added', htmlspecialchars($username))
132 );
133 break;
134 case 'edit':
135 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
136 $_SESSION['return'][] = array(
137 'type' => 'danger',
138 'log' => array(__FUNCTION__, $_action, $_data_log),
139 'msg' => 'access_denied'
140 );
141 return false;
142 }
143 // Administrator
144 if ($_SESSION['mailcow_cc_role'] == "admin") {
145 if (!is_array($_data['username'])) {
146 $usernames = array();
147 $usernames[] = $_data['username'];
148 }
149 else {
150 $usernames = $_data['username'];
151 }
152 foreach ($usernames as $username) {
153 $is_now = domain_admin('details', $username);
154 $domains = (isset($_data['domains'])) ? (array)$_data['domains'] : null;
155 if (!empty($is_now)) {
156 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
157 $domains = (!empty($domains)) ? $domains : $is_now['selected_domains'];
158 $username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username'];
159 }
160 else {
161 $_SESSION['return'][] = array(
162 'type' => 'danger',
163 'log' => array(__FUNCTION__, $_action, $_data_log),
164 'msg' => 'access_denied'
165 );
166 continue;
167 }
168 $password = $_data['password'];
169 $password2 = $_data['password2'];
170 if (!empty($domains)) {
171 foreach ($domains as $domain) {
172 if (!is_valid_domain_name($domain) || mailbox('get', 'domain_details', $domain) === false) {
173 $_SESSION['return'][] = array(
174 'type' => 'danger',
175 'log' => array(__FUNCTION__, $_action, $_data_log),
176 'msg' => array('domain_invalid', htmlspecialchars($domain))
177 );
178 continue 2;
179 }
180 }
181 }
182 if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) {
183 $_SESSION['return'][] = array(
184 'type' => 'danger',
185 'log' => array(__FUNCTION__, $_action, $_data_log),
186 'msg' => array('username_invalid', $username_new)
187 );
188 continue;
189 }
190 if ($username_new != $username) {
191 if (!empty(domain_admin('details', $username_new)['username'])) {
192 $_SESSION['return'][] = array(
193 'type' => 'danger',
194 'log' => array(__FUNCTION__, $_action, $_data_log),
195 'msg' => array('username_invalid', $username_new)
196 );
197 continue;
198 }
199 }
200 $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
201 $stmt->execute(array(
202 ':username' => $username,
203 ));
204 $stmt = $pdo->prepare("UPDATE `da_acl` SET `username` = :username_new WHERE `username` = :username");
205 $stmt->execute(array(
206 ':username_new' => $username_new,
207 ':username' => $username
208 ));
209 if (!empty($domains)) {
210 foreach ($domains as $domain) {
211 $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
212 VALUES (:username_new, :domain, :created, :active)");
213 $stmt->execute(array(
214 ':username_new' => $username_new,
215 ':domain' => $domain,
216 ':created' => date('Y-m-d H:i:s'),
217 ':active' => $active
218 ));
219 }
220 }
221 if (!empty($password) && !empty($password2)) {
222 if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
223 $_SESSION['return'][] = array(
224 'type' => 'danger',
225 'log' => array(__FUNCTION__, $_action, $_data_log),
226 'msg' => 'password_complexity'
227 );
228 continue;
229 }
230 if ($password != $password2) {
231 $_SESSION['return'][] = array(
232 'type' => 'danger',
233 'log' => array(__FUNCTION__, $_action, $_data_log),
234 'msg' => 'password_mismatch'
235 );
236 continue;
237 }
238 $password_hashed = hash_password($password);
239 $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
240 $stmt->execute(array(
241 ':password_hashed' => $password_hashed,
242 ':username_new' => $username_new,
243 ':username' => $username,
244 ':active' => $active
245 ));
246 if (isset($_data['disable_tfa'])) {
247 $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
248 $stmt->execute(array(':username' => $username));
249 }
250 else {
251 $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
252 $stmt->execute(array(':username_new' => $username_new, ':username' => $username));
253 }
254 }
255 else {
256 $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username");
257 $stmt->execute(array(
258 ':username_new' => $username_new,
259 ':username' => $username,
260 ':active' => $active
261 ));
262 if (isset($_data['disable_tfa'])) {
263 $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username");
264 $stmt->execute(array(':username' => $username));
265 }
266 else {
267 $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
268 $stmt->execute(array(':username_new' => $username_new, ':username' => $username));
269 }
270 }
271 $_SESSION['return'][] = array(
272 'type' => 'success',
273 'log' => array(__FUNCTION__, $_action, $_data_log),
274 'msg' => array('domain_admin_modified', htmlspecialchars($username))
275 );
276 }
277 return true;
278 }
279 // Domain administrator
280 // Can only edit itself
281 elseif ($_SESSION['mailcow_cc_role'] == "domainadmin") {
282 $username = $_SESSION['mailcow_cc_username'];
283 $password_old = $_data['user_old_pass'];
284 $password_new = $_data['user_new_pass'];
285 $password_new2 = $_data['user_new_pass2'];
286
287 $stmt = $pdo->prepare("SELECT `password` FROM `admin`
288 WHERE `username` = :user");
289 $stmt->execute(array(':user' => $username));
290 $row = $stmt->fetch(PDO::FETCH_ASSOC);
291 if (!verify_hash($row['password'], $password_old)) {
292 $_SESSION['return'][] = array(
293 'type' => 'danger',
294 'log' => array(__FUNCTION__, $_action, $_data_log),
295 'msg' => 'access_denied'
296 );
297 return false;
298 }
299 if (!empty($password_new2) && !empty($password_new)) {
300 if ($password_new2 != $password_new) {
301 $_SESSION['return'][] = array(
302 'type' => 'danger',
303 'log' => array(__FUNCTION__, $_action, $_data_log),
304 'msg' => 'password_mismatch'
305 );
306 return false;
307 }
308 if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) {
309 $_SESSION['return'][] = array(
310 'type' => 'danger',
311 'log' => array(__FUNCTION__, $_action, $_data_log),
312 'msg' => 'password_complexity'
313 );
314 return false;
315 }
316 $password_hashed = hash_password($password_new);
317 $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
318 $stmt->execute(array(
319 ':password_hashed' => $password_hashed,
320 ':username' => $username
321 ));
322 }
323 $_SESSION['return'][] = array(
324 'type' => 'success',
325 'log' => array(__FUNCTION__, $_action, $_data_log),
326 'msg' => array('domain_admin_modified', htmlspecialchars($username))
327 );
328 }
329 break;
330 case 'delete':
331 if ($_SESSION['mailcow_cc_role'] != "admin") {
332 $_SESSION['return'][] = array(
333 'type' => 'danger',
334 'log' => array(__FUNCTION__, $_action, $_data_log),
335 'msg' => 'access_denied'
336 );
337 return false;
338 }
339 $usernames = (array)$_data['username'];
340 foreach ($usernames as $username) {
341 if (empty(domain_admin('details', $username))) {
342 $_SESSION['return'][] = array(
343 'type' => 'danger',
344 'log' => array(__FUNCTION__, $_action, $_data_log),
345 'msg' => array('username_invalid', $username)
346 );
347 continue;
348 }
349 $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
350 $stmt->execute(array(
351 ':username' => $username,
352 ));
353 $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username");
354 $stmt->execute(array(
355 ':username' => $username,
356 ));
357 $stmt = $pdo->prepare("DELETE FROM `da_acl` WHERE `username` = :username");
358 $stmt->execute(array(
359 ':username' => $username,
360 ));
361 $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
362 $stmt->execute(array(
363 ':username' => $username,
364 ));
365 $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
366 $stmt->execute(array(
367 ':username' => $username,
368 ));
369 $_SESSION['return'][] = array(
370 'type' => 'success',
371 'log' => array(__FUNCTION__, $_action, $_data_log),
372 'msg' => array('domain_admin_removed', htmlspecialchars($username))
373 );
374 }
375 break;
376 case 'get':
377 $domainadmins = array();
378 if ($_SESSION['mailcow_cc_role'] != "admin") {
379 $_SESSION['return'][] = array(
380 'type' => 'danger',
381 'log' => array(__FUNCTION__, $_action, $_data_log),
382 'msg' => 'access_denied'
383 );
384 return false;
385 }
386 $stmt = $pdo->query("SELECT DISTINCT
387 `username`
388 FROM `domain_admins`
389 WHERE `username` IN (
390 SELECT `username` FROM `admin`
391 WHERE `superadmin`!='1'
392 )");
393 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
394 while ($row = array_shift($rows)) {
395 $domainadmins[] = $row['username'];
396 }
397 return $domainadmins;
398 break;
399 case 'details':
400 $domainadmindata = array();
401 if ($_SESSION['mailcow_cc_role'] == "domainadmin" && $_data != $_SESSION['mailcow_cc_username']) {
402 return false;
403 }
404 elseif ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) {
405 return false;
406 }
407 if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $_data))) {
408 return false;
409 }
410 $stmt = $pdo->prepare("SELECT
411 `tfa`.`active` AS `tfa_active`,
412 `domain_admins`.`username`,
413 `domain_admins`.`created`,
414 `domain_admins`.`active` AS `active`
415 FROM `domain_admins`
416 LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`domain_admins`.`username`
417 WHERE `domain_admins`.`username`= :domain_admin");
418 $stmt->execute(array(
419 ':domain_admin' => $_data
420 ));
421 $row = $stmt->fetch(PDO::FETCH_ASSOC);
422 if (empty($row)) {
423 return false;
424 }
425 $domainadmindata['username'] = $row['username'];
426 $domainadmindata['tfa_active'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active'];
427 $domainadmindata['tfa_active_int'] = (is_null($row['tfa_active'])) ? 0 : $row['tfa_active'];
428 $domainadmindata['active'] = $row['active'];
429 $domainadmindata['active_int'] = $row['active'];
430 $domainadmindata['created'] = $row['created'];
431 // GET SELECTED
432 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
433 WHERE `domain` IN (
434 SELECT `domain` FROM `domain_admins`
435 WHERE `username`= :domain_admin)");
436 $stmt->execute(array(':domain_admin' => $_data));
437 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
438 while($row = array_shift($rows)) {
439 $domainadmindata['selected_domains'][] = $row['domain'];
440 }
441 // GET UNSELECTED
442 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
443 WHERE `domain` NOT IN (
444 SELECT `domain` FROM `domain_admins`
445 WHERE `username`= :domain_admin)");
446 $stmt->execute(array(':domain_admin' => $_data));
447 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
448 while($row = array_shift($rows)) {
449 $domainadmindata['unselected_domains'][] = $row['domain'];
450 }
451 if (!isset($domainadmindata['unselected_domains'])) {
452 $domainadmindata['unselected_domains'] = "";
453 }
454
455 return $domainadmindata;
456 break;
457 }
458}