blob: 21b6b130b8527a6b4ed4065c4e5fc5594f01ed8f [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
2function mailbox($_action, $_type, $_data = null, $_extra = null) {
3 global $pdo;
4 global $redis;
5 global $lang;
6 global $MAILBOX_DEFAULT_ATTRIBUTES;
7 $_data_log = $_data;
8 !isset($_data_log['password']) ?: $_data_log['password'] = '*';
9 !isset($_data_log['password2']) ?: $_data_log['password2'] = '*';
10 switch ($_action) {
11 case 'add':
12 switch ($_type) {
13 case 'time_limited_alias':
14 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
15 $_SESSION['return'][] = array(
16 'type' => 'danger',
17 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
18 'msg' => 'access_denied'
19 );
20 return false;
21 }
22 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
23 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
24 $_SESSION['return'][] = array(
25 'type' => 'danger',
26 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
27 'msg' => 'access_denied'
28 );
29 return false;
30 }
31 else {
32 $username = $_data['username'];
33 }
34 }
35 else {
36 $username = $_SESSION['mailcow_cc_username'];
37 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020038 if (isset($_data["validity"]) && !filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010039 $_SESSION['return'][] = array(
40 'type' => 'danger',
41 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
42 'msg' => 'validity_missing'
43 );
44 return false;
45 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020046 else {
47 // Default to 1 yr
48 $_data["validity"] = 8760;
49 }
50 $domain = $_data['domain'];
51 $valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
52 $valid_alias_domains = user_get_alias_details($username)['alias_domains'];
53 if (!empty($valid_alias_domains)) {
54 $valid_domains = array_merge($valid_domains, $valid_alias_domains);
55 }
56 if (!in_array($domain, $valid_domains)) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010057 $_SESSION['return'][] = array(
58 'type' => 'danger',
59 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
60 'msg' => 'domain_invalid'
61 );
62 return false;
63 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020064 $validity = strtotime("+" . $_data["validity"] . " hour");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010065 $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `goto`, `validity`) VALUES
66 (:address, :goto, :validity)");
67 $stmt->execute(array(
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020068 ':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010069 ':goto' => $username,
70 ':validity' => $validity
71 ));
72 $_SESSION['return'][] = array(
73 'type' => 'success',
74 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
75 'msg' => array('mailbox_modified', $username)
76 );
77 break;
78 case 'global_filter':
79 if ($_SESSION['mailcow_cc_role'] != "admin") {
80 $_SESSION['return'][] = array(
81 'type' => 'danger',
82 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
83 'msg' => 'access_denied'
84 );
85 return false;
86 }
87 $sieve = new Sieve\SieveParser();
88 $script_data = $_data['script_data'];
89 $script_data = str_replace("\r\n", "\n", $script_data); // windows -> unix
90 $script_data = str_replace("\r", "\n", $script_data); // remaining -> unix
91 $filter_type = $_data['filter_type'];
92 try {
93 $sieve->parse($script_data);
94 }
95 catch (Exception $e) {
96 $_SESSION['return'][] = array(
97 'type' => 'danger',
98 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
99 'msg' => array('sieve_error', $e->getMessage())
100 );
101 return false;
102 }
103 if ($filter_type == 'prefilter') {
104 try {
105 if (file_exists('/global_sieve/before')) {
106 $filter_handle = fopen('/global_sieve/before', 'w');
107 if (!$filter_handle) {
108 throw new Exception($lang['danger']['file_open_error']);
109 }
110 fwrite($filter_handle, $script_data);
111 fclose($filter_handle);
112 }
113 $restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
114 if ($restart_response['type'] == "success") {
115 $_SESSION['return'][] = array(
116 'type' => 'success',
117 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
118 'msg' => 'dovecot_restart_success'
119 );
120 }
121 else {
122 $_SESSION['return'][] = array(
123 'type' => 'warning',
124 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
125 'msg' => 'dovecot_restart_failed'
126 );
127 }
128 }
129 catch (Exception $e) {
130 $_SESSION['return'][] = array(
131 'type' => 'danger',
132 'log' => array(__FUNCTION__, $_action, $_data_log),
133 'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
134 );
135 return false;
136 }
137 }
138 elseif ($filter_type == 'postfilter') {
139 try {
140 if (file_exists('/global_sieve/after')) {
141 $filter_handle = fopen('/global_sieve/after', 'w');
142 if (!$filter_handle) {
143 throw new Exception($lang['danger']['file_open_error']);
144 }
145 fwrite($filter_handle, $script_data);
146 fclose($filter_handle);
147 }
148 $restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
149 if ($restart_response['type'] == "success") {
150 $_SESSION['return'][] = array(
151 'type' => 'success',
152 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
153 'msg' => 'dovecot_restart_success'
154 );
155 }
156 else {
157 $_SESSION['return'][] = array(
158 'type' => 'warning',
159 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
160 'msg' => 'dovecot_restart_failed'
161 );
162 }
163 }
164 catch (Exception $e) {
165 $_SESSION['return'][] = array(
166 'type' => 'danger',
167 'log' => array(__FUNCTION__, $_action, $_data_log),
168 'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
169 );
170 return false;
171 }
172 }
173 else {
174 $_SESSION['return'][] = array(
175 'type' => 'danger',
176 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
177 'msg' => 'invalid_filter_type'
178 );
179 return false;
180 }
181 $_SESSION['return'][] = array(
182 'type' => 'success',
183 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
184 'msg' => 'global_filter_written'
185 );
186 return true;
187 case 'filter':
188 $sieve = new Sieve\SieveParser();
189 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
190 $_SESSION['return'][] = array(
191 'type' => 'danger',
192 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
193 'msg' => 'access_denied'
194 );
195 return false;
196 }
197 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
198 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
199 $_SESSION['return'][] = array(
200 'type' => 'danger',
201 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
202 'msg' => 'access_denied'
203 );
204 return false;
205 }
206 else {
207 $username = $_data['username'];
208 }
209 }
210 elseif ($_SESSION['mailcow_cc_role'] == "user") {
211 $username = $_SESSION['mailcow_cc_username'];
212 }
213 else {
214 $_SESSION['return'][] = array(
215 'type' => 'danger',
216 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
217 'msg' => 'no_user_defined'
218 );
219 return false;
220 }
221 $active = intval($_data['active']);
222 $script_data = $_data['script_data'];
223 $script_desc = $_data['script_desc'];
224 $filter_type = $_data['filter_type'];
225 if (empty($script_data)) {
226 $_SESSION['return'][] = array(
227 'type' => 'danger',
228 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
229 'msg' => 'script_empty'
230 );
231 return false;
232 }
233 try {
234 $sieve->parse($script_data);
235 }
236 catch (Exception $e) {
237 $_SESSION['return'][] = array(
238 'type' => 'danger',
239 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
240 'msg' => array('sieve_error', $e->getMessage())
241 );
242 return false;
243 }
244 if (empty($script_data) || empty($script_desc)) {
245 $_SESSION['return'][] = array(
246 'type' => 'danger',
247 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
248 'msg' => 'value_missing'
249 );
250 return false;
251 }
252 if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
253 $_SESSION['return'][] = array(
254 'type' => 'danger',
255 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
256 'msg' => 'filter_type'
257 );
258 return false;
259 }
260 if (!empty($active)) {
261 $script_name = 'active';
262 $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type");
263 $stmt->execute(array(
264 ':username' => $username,
265 ':filter_type' => $filter_type
266 ));
267 }
268 else {
269 $script_name = 'inactive';
270 }
271 $stmt = $pdo->prepare("INSERT INTO `sieve_filters` (`username`, `script_data`, `script_desc`, `script_name`, `filter_type`)
272 VALUES (:username, :script_data, :script_desc, :script_name, :filter_type)");
273 $stmt->execute(array(
274 ':username' => $username,
275 ':script_data' => $script_data,
276 ':script_desc' => $script_desc,
277 ':script_name' => $script_name,
278 ':filter_type' => $filter_type
279 ));
280 $_SESSION['return'][] = array(
281 'type' => 'success',
282 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
283 'msg' => array('mailbox_modified', $username)
284 );
285 break;
286 case 'syncjob':
287 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
288 $_SESSION['return'][] = array(
289 'type' => 'danger',
290 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
291 'msg' => 'access_denied'
292 );
293 return false;
294 }
295 if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
296 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
297 $_SESSION['return'][] = array(
298 'type' => 'danger',
299 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
300 'msg' => 'access_denied'
301 );
302 return false;
303 }
304 else {
305 $username = $_data['username'];
306 }
307 }
308 elseif ($_SESSION['mailcow_cc_role'] == "user") {
309 $username = $_SESSION['mailcow_cc_username'];
310 }
311 else {
312 $_SESSION['return'][] = array(
313 'type' => 'danger',
314 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
315 'msg' => 'no_user_defined'
316 );
317 return false;
318 }
319 $active = intval($_data['active']);
320 $subscribeall = intval($_data['subscribeall']);
321 $delete2duplicates = intval($_data['delete2duplicates']);
322 $delete1 = intval($_data['delete1']);
323 $delete2 = intval($_data['delete2']);
324 $timeout1 = intval($_data['timeout1']);
325 $timeout2 = intval($_data['timeout2']);
326 $skipcrossduplicates = intval($_data['skipcrossduplicates']);
327 $automap = intval($_data['automap']);
328 $port1 = $_data['port1'];
329 $host1 = strtolower($_data['host1']);
330 $password1 = $_data['password1'];
331 $exclude = $_data['exclude'];
332 $maxage = $_data['maxage'];
333 $maxbytespersecond = $_data['maxbytespersecond'];
334 $subfolder2 = $_data['subfolder2'];
335 $user1 = $_data['user1'];
336 $mins_interval = $_data['mins_interval'];
337 $enc1 = $_data['enc1'];
338 $custom_params = (empty(trim($_data['custom_params']))) ? '' : trim($_data['custom_params']);
339 // Workaround, fixme
340 if (strpos($custom_params, 'pipemess')) {
341 $custom_params = '';
342 }
343 if (empty($subfolder2)) {
344 $subfolder2 = "";
345 }
346 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
347 $maxage = "0";
348 }
349 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
350 $timeout1 = "600";
351 }
352 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
353 $timeout2 = "600";
354 }
355 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
356 $maxbytespersecond = "0";
357 }
358 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
359 $_SESSION['return'][] = array(
360 'type' => 'danger',
361 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
362 'msg' => 'access_denied'
363 );
364 return false;
365 }
366 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
367 $_SESSION['return'][] = array(
368 'type' => 'danger',
369 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
370 'msg' => 'access_denied'
371 );
372 return false;
373 }
374 // if (!is_valid_domain_name($host1)) {
375 // $_SESSION['return'][] = array(
376 // 'type' => 'danger',
377 // 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
378 // 'msg' => 'access_denied'
379 // );
380 // return false;
381 // }
382 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
383 $_SESSION['return'][] = array(
384 'type' => 'danger',
385 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
386 'msg' => 'access_denied'
387 );
388 return false;
389 }
390 if (@preg_match("/" . $exclude . "/", null) === false) {
391 $_SESSION['return'][] = array(
392 'type' => 'danger',
393 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
394 'msg' => 'access_denied'
395 );
396 return false;
397 }
398 $stmt = $pdo->prepare("SELECT '1' FROM `imapsync`
399 WHERE `user2` = :user2 AND `user1` = :user1 AND `host1` = :host1");
400 $stmt->execute(array(':user1' => $user1, ':user2' => $username, ':host1' => $host1));
401 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
402 if ($num_results != 0) {
403 $_SESSION['return'][] = array(
404 'type' => 'danger',
405 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
406 'msg' => array('object_exists', htmlspecialchars($host1 . ' / ' . $user1))
407 );
408 return false;
409 }
410 $stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `delete2`, `timeout1`, `timeout2`, `automap`, `skipcrossduplicates`, `maxbytespersecond`, `subscribeall`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `custom_params`, `active`)
411 VALUES (:user2, :exclude, :delete1, :delete2, :timeout1, :timeout2, :automap, :skipcrossduplicates, :maxbytespersecond, :subscribeall, :maxage, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :custom_params, :active)");
412 $stmt->execute(array(
413 ':user2' => $username,
414 ':custom_params' => $custom_params,
415 ':exclude' => $exclude,
416 ':maxage' => $maxage,
417 ':delete1' => $delete1,
418 ':delete2' => $delete2,
419 ':timeout1' => $timeout1,
420 ':timeout2' => $timeout2,
421 ':automap' => $automap,
422 ':skipcrossduplicates' => $skipcrossduplicates,
423 ':maxbytespersecond' => $maxbytespersecond,
424 ':subscribeall' => $subscribeall,
425 ':subfolder2' => $subfolder2,
426 ':host1' => $host1,
427 ':authmech1' => 'PLAIN',
428 ':user1' => $user1,
429 ':password1' => $password1,
430 ':mins_interval' => $mins_interval,
431 ':port1' => $port1,
432 ':enc1' => $enc1,
433 ':delete2duplicates' => $delete2duplicates,
434 ':active' => $active,
435 ));
436 $_SESSION['return'][] = array(
437 'type' => 'success',
438 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
439 'msg' => array('mailbox_modified', $username)
440 );
441 break;
442 case 'domain':
443 if ($_SESSION['mailcow_cc_role'] != "admin") {
444 $_SESSION['return'][] = array(
445 'type' => 'danger',
446 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
447 'msg' => 'access_denied'
448 );
449 return false;
450 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200451 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100452 $description = $_data['description'];
453 if (empty($description)) {
454 $description = $domain;
455 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200456 $aliases = (int)$_data['aliases'];
457 $mailboxes = (int)$_data['mailboxes'];
458 $defquota = (int)$_data['defquota'];
459 $maxquota = (int)$_data['maxquota'];
460 $restart_sogo = (int)$_data['restart_sogo'];
461 $quota = (int)$_data['quota'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100462 if ($defquota > $maxquota) {
463 $_SESSION['return'][] = array(
464 'type' => 'danger',
465 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
466 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
467 );
468 return false;
469 }
470 if ($maxquota > $quota) {
471 $_SESSION['return'][] = array(
472 'type' => 'danger',
473 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
474 'msg' => 'mailbox_quota_exceeds_domain_quota'
475 );
476 return false;
477 }
478 if ($defquota == "0" || empty($defquota)) {
479 $_SESSION['return'][] = array(
480 'type' => 'danger',
481 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
482 'msg' => 'defquota_empty'
483 );
484 return false;
485 }
486 if ($maxquota == "0" || empty($maxquota)) {
487 $_SESSION['return'][] = array(
488 'type' => 'danger',
489 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
490 'msg' => 'maxquota_empty'
491 );
492 return false;
493 }
494 $active = intval($_data['active']);
495 $relay_all_recipients = intval($_data['relay_all_recipients']);
496 $relay_unknown_only = intval($_data['relay_unknown_only']);
497 $backupmx = intval($_data['backupmx']);
498 $gal = intval($_data['gal']);
499 if ($relay_all_recipients == 1) {
500 $backupmx = '1';
501 }
502 if ($relay_unknown_only == 1) {
503 $backupmx = 1;
504 $relay_all_recipients = 1;
505 }
506 if (!is_valid_domain_name($domain)) {
507 $_SESSION['return'][] = array(
508 'type' => 'danger',
509 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
510 'msg' => 'domain_invalid'
511 );
512 return false;
513 }
514 foreach (array($quota, $maxquota, $mailboxes, $aliases) as $data) {
515 if (!is_numeric($data)) {
516 $_SESSION['return'][] = array(
517 'type' => 'danger',
518 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
519 'msg' => array('object_is_not_numeric', htmlspecialchars($data))
520 );
521 return false;
522 }
523 }
524 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
525 WHERE `domain` = :domain");
526 $stmt->execute(array(':domain' => $domain));
527 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
528 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
529 WHERE `alias_domain` = :domain");
530 $stmt->execute(array(':domain' => $domain));
531 $num_results = $num_results + count($stmt->fetchAll(PDO::FETCH_ASSOC));
532 if ($num_results != 0) {
533 $_SESSION['return'][] = array(
534 'type' => 'danger',
535 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
536 'msg' => array('domain_exists', htmlspecialchars($domain))
537 );
538 return false;
539 }
540 if ($domain == getenv('MAILCOW_HOSTNAME')) {
541 $_SESSION['return'][] = array(
542 'type' => 'danger',
543 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
544 'msg' => 'domain_cannot_match_hostname'
545 );
546 return false;
547 }
548 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
549 $stmt->execute(array(
550 ':domain' => '%@' . $domain
551 ));
552 $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
553 VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
554 $stmt->execute(array(
555 ':domain' => $domain,
556 ':description' => $description,
557 ':aliases' => $aliases,
558 ':mailboxes' => $mailboxes,
559 ':defquota' => $defquota,
560 ':maxquota' => $maxquota,
561 ':quota' => $quota,
562 ':backupmx' => $backupmx,
563 ':gal' => $gal,
564 ':active' => $active,
565 ':relay_unknown_only' => $relay_unknown_only,
566 ':relay_all_recipients' => $relay_all_recipients
567 ));
568 try {
569 $redis->hSet('DOMAIN_MAP', $domain, 1);
570 }
571 catch (RedisException $e) {
572 $_SESSION['return'][] = array(
573 'type' => 'danger',
574 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
575 'msg' => array('redis_error', $e)
576 );
577 return false;
578 }
579 if (!empty(intval($_data['rl_value']))) {
580 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
581 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100582 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
583 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
584 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100585 if (!empty($restart_sogo)) {
586 $restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
587 if ($restart_response['type'] == "success") {
588 $_SESSION['return'][] = array(
589 'type' => 'success',
590 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
591 'msg' => array('domain_added', htmlspecialchars($domain))
592 );
593 return true;
594 }
595 else {
596 $_SESSION['return'][] = array(
597 'type' => 'warning',
598 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
599 'msg' => 'domain_added_sogo_failed'
600 );
601 return false;
602 }
603 }
604 $_SESSION['return'][] = array(
605 'type' => 'success',
606 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
607 'msg' => array('domain_added', htmlspecialchars($domain))
608 );
609 return true;
610 break;
611 case 'alias':
612 $addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
613 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
614 $active = intval($_data['active']);
615 $sogo_visible = intval($_data['sogo_visible']);
616 $goto_null = intval($_data['goto_null']);
617 $goto_spam = intval($_data['goto_spam']);
618 $goto_ham = intval($_data['goto_ham']);
619 $private_comment = $_data['private_comment'];
620 $public_comment = $_data['public_comment'];
621 if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
622 $_SESSION['return'][] = array(
623 'type' => 'danger',
624 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
625 'msg' => 'comment_too_long'
626 );
627 return false;
628 }
629 if (empty($addresses[0])) {
630 $_SESSION['return'][] = array(
631 'type' => 'danger',
632 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
633 'msg' => 'alias_empty'
634 );
635 return false;
636 }
637 if (empty($gotos[0]) && ($goto_null + $goto_spam + $goto_ham == 0)) {
638 $_SESSION['return'][] = array(
639 'type' => 'danger',
640 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
641 'msg' => 'goto_empty'
642 );
643 return false;
644 }
645 if ($goto_null == "1") {
646 $goto = "null@localhost";
647 }
648 elseif ($goto_spam == "1") {
649 $goto = "spam@localhost";
650 }
651 elseif ($goto_ham == "1") {
652 $goto = "ham@localhost";
653 }
654 else {
655 foreach ($gotos as $i => &$goto) {
656 if (empty($goto)) {
657 continue;
658 }
659 $goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
660 $goto_local_part = strstr($goto, '@', true);
661 $goto = $goto_local_part.'@'.$goto_domain;
662 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
663 WHERE `kind` REGEXP 'location|thing|group'
664 AND `username`= :goto");
665 $stmt->execute(array(':goto' => $goto));
666 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
667 if ($num_results != 0) {
668 $_SESSION['return'][] = array(
669 'type' => 'danger',
670 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
671 'msg' => array('goto_invalid', htmlspecialchars($goto))
672 );
673 unset($gotos[$i]);
674 continue;
675 }
676 if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
677 $_SESSION['return'][] = array(
678 'type' => 'danger',
679 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
680 'msg' => array('goto_invalid', htmlspecialchars($goto))
681 );
682 unset($gotos[$i]);
683 continue;
684 }
685 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200686 $gotos = array_unique($gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100687 $gotos = array_filter($gotos);
688 if (empty($gotos)) { return false; }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200689 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100690 }
691 foreach ($addresses as $address) {
692 if (empty($address)) {
693 continue;
694 }
695 if (in_array($address, $gotos)) {
696 continue;
697 }
698 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
699 $local_part = strstr($address, '@', true);
700 $address = $local_part.'@'.$domain;
701 $domaindata = mailbox('get', 'domain_details', $domain);
702 if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
703 $_SESSION['return'][] = array(
704 'type' => 'danger',
705 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
706 'msg' => 'max_alias_exceeded'
707 );
708 return false;
709 }
710 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
711 WHERE `address`= :address OR `address` IN (
712 SELECT `username` FROM `mailbox`, `alias_domain`
713 WHERE (
714 `alias_domain`.`alias_domain` = :address_d
715 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
716 $stmt->execute(array(
717 ':address' => $address,
718 ':address_l' => $local_part,
719 ':address_d' => $domain
720 ));
721 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
722 if ($num_results != 0) {
723 $_SESSION['return'][] = array(
724 'type' => 'danger',
725 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
726 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
727 );
728 continue;
729 }
730 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
731 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
732 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
733 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
734 if ($num_results == 0) {
735 $_SESSION['return'][] = array(
736 'type' => 'danger',
737 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
738 'msg' => array('domain_not_found', htmlspecialchars($domain))
739 );
740 continue;
741 }
742 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
743 WHERE `address`= :address");
744 $stmt->execute(array(':address' => $address));
745 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
746 if ($num_results != 0) {
747 $_SESSION['return'][] = array(
748 'type' => 'danger',
749 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
750 'msg' => array('is_spam_alias', htmlspecialchars($address))
751 );
752 continue;
753 }
754 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
755 $_SESSION['return'][] = array(
756 'type' => 'danger',
757 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
758 'msg' => array('alias_invalid', $address)
759 );
760 continue;
761 }
762 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
763 $_SESSION['return'][] = array(
764 'type' => 'danger',
765 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
766 'msg' => 'access_denied'
767 );
768 continue;
769 }
770 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `active`)
771 VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :active)");
772 if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
773 $stmt->execute(array(
774 ':address' => '@'.$domain,
775 ':public_comment' => $public_comment,
776 ':private_comment' => $private_comment,
777 ':address' => '@'.$domain,
778 ':goto' => $goto,
779 ':domain' => $domain,
780 ':sogo_visible' => $sogo_visible,
781 ':active' => $active
782 ));
783 }
784 else {
785 $stmt->execute(array(
786 ':address' => $address,
787 ':public_comment' => $public_comment,
788 ':private_comment' => $private_comment,
789 ':goto' => $goto,
790 ':domain' => $domain,
791 ':sogo_visible' => $sogo_visible,
792 ':active' => $active
793 ));
794 }
795 $id = $pdo->lastInsertId();
796 $_SESSION['return'][] = array(
797 'type' => 'success',
798 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
799 'msg' => array('alias_added', $address, $id)
800 );
801 }
802 break;
803 case 'alias_domain':
804 $active = intval($_data['active']);
805 $alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain']));
806 $alias_domains = array_filter($alias_domains);
807 $target_domain = idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46);
808 if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) {
809 $_SESSION['return'][] = array(
810 'type' => 'danger',
811 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
812 'msg' => 'access_denied'
813 );
814 return false;
815 }
816 if (!is_valid_domain_name($target_domain)) {
817 $_SESSION['return'][] = array(
818 'type' => 'danger',
819 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
820 'msg' => 'target_domain_invalid'
821 );
822 return false;
823 }
824 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
825 $_SESSION['return'][] = array(
826 'type' => 'danger',
827 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
828 'msg' => 'access_denied'
829 );
830 return false;
831 }
832 foreach ($alias_domains as $i => $alias_domain) {
833 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
834 if (!is_valid_domain_name($alias_domain)) {
835 $_SESSION['return'][] = array(
836 'type' => 'danger',
837 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
838 'msg' => array('alias_domain_invalid', htmlspecialchars(alias_domain))
839 );
840 continue;
841 }
842 if ($alias_domain == $target_domain) {
843 $_SESSION['return'][] = array(
844 'type' => 'danger',
845 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
846 'msg' => array('aliasd_targetd_identical', htmlspecialchars($target_domain))
847 );
848 continue;
849 }
850 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
851 WHERE `domain`= :target_domain");
852 $stmt->execute(array(':target_domain' => $target_domain));
853 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
854 if ($num_results == 0) {
855 $_SESSION['return'][] = array(
856 'type' => 'danger',
857 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
858 'msg' => array('targetd_not_found', htmlspecialchars($target_domain))
859 );
860 continue;
861 }
862 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
863 WHERE `domain`= :target_domain AND `backupmx` = '1'");
864 $stmt->execute(array(':target_domain' => $target_domain));
865 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
866 if ($num_results == 1) {
867 $_SESSION['return'][] = array(
868 'type' => 'danger',
869 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
870 'msg' => array('targetd_relay_domain', htmlspecialchars($target_domain))
871 );
872 continue;
873 }
874 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain
875 UNION
876 SELECT `domain` FROM `domain` WHERE `domain`= :alias_domain_in_domain");
877 $stmt->execute(array(':alias_domain' => $alias_domain, ':alias_domain_in_domain' => $alias_domain));
878 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
879 if ($num_results != 0) {
880 $_SESSION['return'][] = array(
881 'type' => 'danger',
882 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
883 'msg' => array('alias_domain_invalid', $alias_domain)
884 );
885 continue;
886 }
887 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
888 $stmt->execute(array(
889 ':domain' => '%@' . $domain
890 ));
891 $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
892 VALUES (:alias_domain, :target_domain, :active)");
893 $stmt->execute(array(
894 ':alias_domain' => $alias_domain,
895 ':target_domain' => $target_domain,
896 ':active' => $active
897 ));
898 try {
899 $redis->hSet('DOMAIN_MAP', $alias_domain, 1);
900 }
901 catch (RedisException $e) {
902 $_SESSION['return'][] = array(
903 'type' => 'danger',
904 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
905 'msg' => array('redis_error', $e)
906 );
907 return false;
908 }
909 if (!empty(intval($_data['rl_value']))) {
910 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
911 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100912 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
913 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
914 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100915 $_SESSION['return'][] = array(
916 'type' => 'success',
917 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
918 'msg' => array('aliasd_added', htmlspecialchars($alias_domain))
919 );
920 }
921 break;
922 case 'mailbox':
923 $local_part = strtolower(trim($_data['local_part']));
924 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
925 $username = $local_part . '@' . $domain;
926 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
927 $_SESSION['return'][] = array(
928 'type' => 'danger',
929 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
930 'msg' => 'mailbox_invalid'
931 );
932 return false;
933 }
934 if (empty($_data['local_part'])) {
935 $_SESSION['return'][] = array(
936 'type' => 'danger',
937 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
938 'msg' => 'mailbox_invalid'
939 );
940 return false;
941 }
942 $password = $_data['password'];
943 $password2 = $_data['password2'];
944 $name = ltrim(rtrim($_data['name'], '>'), '<');
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200945 $quota_m = intval($_data['quota']);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100946 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
947 $_SESSION['return'][] = array(
948 'type' => 'danger',
949 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
950 'msg' => 'unlimited_quota_acl'
951 );
952 return false;
953 }
954 if (empty($name)) {
955 $name = $local_part;
956 }
957 $active = intval($_data['active']);
958 $force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
959 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
960 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
961 $sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
962 $imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
963 $pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
964 $smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100965 $sieve_access = (isset($_data['sieve_access'])) ? intval($_data['sieve_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200966 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100967 $quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
968 $quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200969 $quota_b = ($quota_m * 1048576);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100970 $mailbox_attrs = json_encode(
971 array(
972 'force_pw_update' => strval($force_pw_update),
973 'tls_enforce_in' => strval($tls_enforce_in),
974 'tls_enforce_out' => strval($tls_enforce_out),
975 'sogo_access' => strval($sogo_access),
976 'imap_access' => strval($imap_access),
977 'pop3_access' => strval($pop3_access),
978 'smtp_access' => strval($smtp_access),
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100979 'sieve_access' => strval($sieve_access),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200980 'relayhost' => strval($relayhost),
981 'passwd_update' => time(),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100982 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
983 'quarantine_notification' => strval($quarantine_notification),
984 'quarantine_category' => strval($quarantine_category)
985 )
986 );
987 if (!is_valid_domain_name($domain)) {
988 $_SESSION['return'][] = array(
989 'type' => 'danger',
990 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
991 'msg' => 'domain_invalid'
992 );
993 return false;
994 }
995 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
996 $_SESSION['return'][] = array(
997 'type' => 'danger',
998 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
999 'msg' => 'access_denied'
1000 );
1001 return false;
1002 }
1003 $stmt = $pdo->prepare("SELECT `mailboxes`, `maxquota`, `quota` FROM `domain`
1004 WHERE `domain` = :domain");
1005 $stmt->execute(array(':domain' => $domain));
1006 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
1007 $stmt = $pdo->prepare("SELECT
1008 COUNT(*) as count,
1009 COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
1010 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001011 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001012 AND `domain` = :domain");
1013 $stmt->execute(array(':domain' => $domain));
1014 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
1015 $stmt = $pdo->prepare("SELECT `local_part` FROM `mailbox` WHERE `local_part` = :local_part and `domain`= :domain");
1016 $stmt->execute(array(':local_part' => $local_part, ':domain' => $domain));
1017 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1018 if ($num_results != 0) {
1019 $_SESSION['return'][] = array(
1020 'type' => 'danger',
1021 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1022 'msg' => array('object_exists', htmlspecialchars($username))
1023 );
1024 return false;
1025 }
1026 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
1027 $stmt->execute(array(':username' => $username));
1028 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1029 if ($num_results != 0) {
1030 $_SESSION['return'][] = array(
1031 'type' => 'danger',
1032 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1033 'msg' => array('is_alias', htmlspecialchars($username))
1034 );
1035 return false;
1036 }
1037 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :username");
1038 $stmt->execute(array(':username' => $username));
1039 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1040 if ($num_results != 0) {
1041 $_SESSION['return'][] = array(
1042 'type' => 'danger',
1043 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1044 'msg' => array('is_spam_alias', htmlspecialchars($username))
1045 );
1046 return false;
1047 }
1048 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1049 $stmt->execute(array(':domain' => $domain));
1050 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1051 if ($num_results == 0) {
1052 $_SESSION['return'][] = array(
1053 'type' => 'danger',
1054 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1055 'msg' => array('domain_not_found', htmlspecialchars($domain))
1056 );
1057 return false;
1058 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001059 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001060 return false;
1061 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001062 $password_hashed = hash_password($password);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001063 if ($MailboxData['count'] >= $DomainData['mailboxes']) {
1064 $_SESSION['return'][] = array(
1065 'type' => 'danger',
1066 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1067 'msg' => array('max_mailbox_exceeded', $MailboxData['count'], $DomainData['mailboxes'])
1068 );
1069 return false;
1070 }
1071 if ($quota_m > $DomainData['maxquota']) {
1072 $_SESSION['return'][] = array(
1073 'type' => 'danger',
1074 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1075 'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota'])
1076 );
1077 return false;
1078 }
1079 if (($MailboxData['quota'] + $quota_m) > $DomainData['quota']) {
1080 $quota_left_m = ($DomainData['quota'] - $MailboxData['quota']);
1081 $_SESSION['return'][] = array(
1082 'type' => 'danger',
1083 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1084 'msg' => array('mailbox_quota_left_exceeded', $quota_left_m)
1085 );
1086 return false;
1087 }
1088 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `active`)
1089 VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :active)");
1090 $stmt->execute(array(
1091 ':username' => $username,
1092 ':password_hashed' => $password_hashed,
1093 ':name' => $name,
1094 ':quota_b' => $quota_b,
1095 ':local_part' => $local_part,
1096 ':domain' => $domain,
1097 ':mailbox_attrs' => $mailbox_attrs,
1098 ':active' => $active
1099 ));
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001100 $stmt = $pdo->prepare("UPDATE `mailbox` SET
1101 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
1102 WHERE `username` = :username");
1103 $stmt->execute(array(
1104 ':username' => $username
1105 ));
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001106 $stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
1107 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1108 $stmt->execute(array(':username' => $username));
1109 $stmt = $pdo->prepare("INSERT INTO `quota2replica` (`username`, `bytes`, `messages`)
1110 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1111 $stmt->execute(array(':username' => $username));
1112 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
1113 VALUES (:username1, :username2, :domain, :active)");
1114 $stmt->execute(array(
1115 ':username1' => $username,
1116 ':username2' => $username,
1117 ':domain' => $domain,
1118 ':active' => $active
1119 ));
1120 $stmt = $pdo->prepare("INSERT INTO `user_acl` (`username`) VALUES (:username)");
1121 $stmt->execute(array(
1122 ':username' => $username
1123 ));
1124 $_SESSION['return'][] = array(
1125 'type' => 'success',
1126 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1127 'msg' => array('mailbox_added', htmlspecialchars($username))
1128 );
1129 break;
1130 case 'resource':
1131 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1132 $description = $_data['description'];
1133 $local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
1134 $name = $local_part . '@' . $domain;
1135 $kind = $_data['kind'];
1136 $multiple_bookings = intval($_data['multiple_bookings']);
1137 $active = intval($_data['active']);
1138 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
1139 $_SESSION['return'][] = array(
1140 'type' => 'danger',
1141 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1142 'msg' => 'resource_invalid'
1143 );
1144 return false;
1145 }
1146 if (empty($description)) {
1147 $_SESSION['return'][] = array(
1148 'type' => 'danger',
1149 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1150 'msg' => 'description_invalid'
1151 );
1152 return false;
1153 }
1154 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
1155 $multiple_bookings = -1;
1156 }
1157 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
1158 $_SESSION['return'][] = array(
1159 'type' => 'danger',
1160 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1161 'msg' => 'resource_invalid'
1162 );
1163 return false;
1164 }
1165 if (!is_valid_domain_name($domain)) {
1166 $_SESSION['return'][] = array(
1167 'type' => 'danger',
1168 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1169 'msg' => 'domain_invalid'
1170 );
1171 return false;
1172 }
1173 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1174 $_SESSION['return'][] = array(
1175 'type' => 'danger',
1176 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1177 'msg' => 'access_denied'
1178 );
1179 return false;
1180 }
1181 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
1182 $stmt->execute(array(':name' => $name));
1183 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1184 if ($num_results != 0) {
1185 $_SESSION['return'][] = array(
1186 'type' => 'danger',
1187 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1188 'msg' => array('object_exists', htmlspecialchars($name))
1189 );
1190 return false;
1191 }
1192 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
1193 $stmt->execute(array(':name' => $name));
1194 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1195 if ($num_results != 0) {
1196 $_SESSION['return'][] = array(
1197 'type' => 'danger',
1198 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1199 'msg' => array('is_alias', htmlspecialchars($name))
1200 );
1201 return false;
1202 }
1203 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
1204 $stmt->execute(array(':name' => $name));
1205 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1206 if ($num_results != 0) {
1207 $_SESSION['return'][] = array(
1208 'type' => 'danger',
1209 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1210 'msg' => array('is_spam_alias', htmlspecialchars($name))
1211 );
1212 return false;
1213 }
1214 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1215 $stmt->execute(array(':domain' => $domain));
1216 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1217 if ($num_results == 0) {
1218 $_SESSION['return'][] = array(
1219 'type' => 'danger',
1220 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1221 'msg' => array('domain_not_found', htmlspecialchars($domain))
1222 );
1223 return false;
1224 }
1225 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`)
1226 VALUES (:name, 'RESOURCE', :description, 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
1227 $stmt->execute(array(
1228 ':name' => $name,
1229 ':description' => $description,
1230 ':local_part' => $local_part,
1231 ':domain' => $domain,
1232 ':active' => $active,
1233 ':kind' => $kind,
1234 ':multiple_bookings' => $multiple_bookings
1235 ));
1236 $_SESSION['return'][] = array(
1237 'type' => 'success',
1238 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1239 'msg' => array('resource_added', htmlspecialchars($name))
1240 );
1241 break;
1242 }
1243 break;
1244 case 'edit':
1245 switch ($_type) {
1246 case 'alias_domain':
1247 $alias_domains = (array)$_data['alias_domain'];
1248 foreach ($alias_domains as $alias_domain) {
1249 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
1250 $is_now = mailbox('get', 'alias_domain_details', $alias_domain);
1251 if (!empty($is_now)) {
1252 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1253 $target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46) : $is_now['target_domain'];
1254 }
1255 else {
1256 $_SESSION['return'][] = array(
1257 'type' => 'danger',
1258 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1259 'msg' => array('alias_domain_invalid', htmlspecialchars($alias_domain))
1260 );
1261 continue;
1262 }
1263 if (!is_valid_domain_name($target_domain)) {
1264 $_SESSION['return'][] = array(
1265 'type' => 'danger',
1266 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1267 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1268 );
1269 continue;
1270 }
1271 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
1272 $_SESSION['return'][] = array(
1273 'type' => 'danger',
1274 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1275 'msg' => 'access_denied'
1276 );
1277 continue;
1278 }
1279 if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) {
1280 $_SESSION['return'][] = array(
1281 'type' => 'danger',
1282 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1283 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1284 );
1285 continue;
1286 }
1287 $stmt = $pdo->prepare("UPDATE `alias_domain` SET
1288 `target_domain` = :target_domain,
1289 `active` = :active
1290 WHERE `alias_domain` = :alias_domain");
1291 $stmt->execute(array(
1292 ':alias_domain' => $alias_domain,
1293 ':target_domain' => $target_domain,
1294 ':active' => $active
1295 ));
1296 $_SESSION['return'][] = array(
1297 'type' => 'success',
1298 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1299 'msg' => array('aliasd_modified', htmlspecialchars($alias_domain))
1300 );
1301 }
1302 break;
1303 case 'tls_policy':
1304 if (!is_array($_data['username'])) {
1305 $usernames = array();
1306 $usernames[] = $_data['username'];
1307 }
1308 else {
1309 $usernames = $_data['username'];
1310 }
1311 if (!isset($_SESSION['acl']['tls_policy']) || $_SESSION['acl']['tls_policy'] != "1" ) {
1312 $_SESSION['return'][] = array(
1313 'type' => 'danger',
1314 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1315 'msg' => 'access_denied'
1316 );
1317 return false;
1318 }
1319 foreach ($usernames as $username) {
1320 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1321 $_SESSION['return'][] = array(
1322 'type' => 'danger',
1323 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1324 'msg' => 'access_denied'
1325 );
1326 continue;
1327 }
1328 $is_now = mailbox('get', 'tls_policy', $username);
1329 if (!empty($is_now)) {
1330 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
1331 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
1332 }
1333 else {
1334 $_SESSION['return'][] = array(
1335 'type' => 'danger',
1336 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1337 'msg' => 'access_denied'
1338 );
1339 continue;
1340 }
1341 $stmt = $pdo->prepare("UPDATE `mailbox`
1342 SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_out),
1343 `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_in)
1344 WHERE `username` = :username");
1345 $stmt->execute(array(
1346 ':tls_out' => intval($tls_enforce_out),
1347 ':tls_in' => intval($tls_enforce_in),
1348 ':username' => $username
1349 ));
1350 $_SESSION['return'][] = array(
1351 'type' => 'success',
1352 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1353 'msg' => array('mailbox_modified', $username)
1354 );
1355 }
1356 break;
1357 case 'quarantine_notification':
1358 if (!is_array($_data['username'])) {
1359 $usernames = array();
1360 $usernames[] = $_data['username'];
1361 }
1362 else {
1363 $usernames = $_data['username'];
1364 }
1365 if (!isset($_SESSION['acl']['quarantine_notification']) || $_SESSION['acl']['quarantine_notification'] != "1" ) {
1366 $_SESSION['return'][] = array(
1367 'type' => 'danger',
1368 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1369 'msg' => 'access_denied'
1370 );
1371 return false;
1372 }
1373 foreach ($usernames as $username) {
1374 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1375 $_SESSION['return'][] = array(
1376 'type' => 'danger',
1377 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1378 'msg' => 'access_denied'
1379 );
1380 continue;
1381 }
1382 $is_now = mailbox('get', 'quarantine_notification', $username);
1383 if (!empty($is_now)) {
1384 $quarantine_notification = (isset($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
1385 }
1386 else {
1387 $_SESSION['return'][] = array(
1388 'type' => 'danger',
1389 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1390 'msg' => 'access_denied'
1391 );
1392 continue;
1393 }
1394 if (!in_array($quarantine_notification, array('never', 'hourly', 'daily', 'weekly'))) {
1395 $_SESSION['return'][] = array(
1396 'type' => 'danger',
1397 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1398 'msg' => 'access_denied'
1399 );
1400 continue;
1401 }
1402 $stmt = $pdo->prepare("UPDATE `mailbox`
1403 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', :quarantine_notification)
1404 WHERE `username` = :username");
1405 $stmt->execute(array(
1406 ':quarantine_notification' => $quarantine_notification,
1407 ':username' => $username
1408 ));
1409 $_SESSION['return'][] = array(
1410 'type' => 'success',
1411 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1412 'msg' => array('mailbox_modified', $username)
1413 );
1414 }
1415 break;
1416 case 'quarantine_category':
1417 if (!is_array($_data['username'])) {
1418 $usernames = array();
1419 $usernames[] = $_data['username'];
1420 }
1421 else {
1422 $usernames = $_data['username'];
1423 }
1424 if (!isset($_SESSION['acl']['quarantine_category']) || $_SESSION['acl']['quarantine_category'] != "1" ) {
1425 $_SESSION['return'][] = array(
1426 'type' => 'danger',
1427 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1428 'msg' => 'access_denied'
1429 );
1430 return false;
1431 }
1432 foreach ($usernames as $username) {
1433 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1434 $_SESSION['return'][] = array(
1435 'type' => 'danger',
1436 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1437 'msg' => 'access_denied'
1438 );
1439 continue;
1440 }
1441 $is_now = mailbox('get', 'quarantine_category', $username);
1442 if (!empty($is_now)) {
1443 $quarantine_category = (isset($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
1444 }
1445 else {
1446 $_SESSION['return'][] = array(
1447 'type' => 'danger',
1448 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1449 'msg' => 'access_denied'
1450 );
1451 continue;
1452 }
1453 if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
1454 $_SESSION['return'][] = array(
1455 'type' => 'danger',
1456 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1457 'msg' => 'access_denied'
1458 );
1459 continue;
1460 }
1461 $stmt = $pdo->prepare("UPDATE `mailbox`
1462 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', :quarantine_category)
1463 WHERE `username` = :username");
1464 $stmt->execute(array(
1465 ':quarantine_category' => $quarantine_category,
1466 ':username' => $username
1467 ));
1468 $_SESSION['return'][] = array(
1469 'type' => 'success',
1470 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1471 'msg' => array('mailbox_modified', $username)
1472 );
1473 }
1474 break;
1475 case 'spam_score':
1476 if (!is_array($_data['username'])) {
1477 $usernames = array();
1478 $usernames[] = $_data['username'];
1479 }
1480 else {
1481 $usernames = $_data['username'];
1482 }
1483 if (!isset($_SESSION['acl']['spam_score']) || $_SESSION['acl']['spam_score'] != "1" ) {
1484 $_SESSION['return'][] = array(
1485 'type' => 'danger',
1486 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1487 'msg' => 'access_denied'
1488 );
1489 return false;
1490 }
1491 foreach ($usernames as $username) {
1492 if ($_data['spam_score'] == "default") {
1493 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1494 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1495 $stmt->execute(array(
1496 ':username' => $username
1497 ));
1498 $_SESSION['return'][] = array(
1499 'type' => 'success',
1500 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1501 'msg' => array('mailbox_modified', $username)
1502 );
1503 continue;
1504 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001505 $lowspamlevel = explode(',', $_data['spam_score'])[0];
1506 $highspamlevel = explode(',', $_data['spam_score'])[1];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001507 if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) {
1508 $_SESSION['return'][] = array(
1509 'type' => 'danger',
1510 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1511 'msg' => 'Invalid spam score, format must be "1,2" where first is low and second is high spam value.'
1512 );
1513 continue;
1514 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001515 if ($lowspamlevel == $highspamlevel) {
1516 $highspamlevel = $highspamlevel + 0.1;
1517 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001518 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1519 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1520 $stmt->execute(array(
1521 ':username' => $username
1522 ));
1523 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1524 VALUES (:username, 'highspamlevel', :highspamlevel)");
1525 $stmt->execute(array(
1526 ':username' => $username,
1527 ':highspamlevel' => $highspamlevel
1528 ));
1529 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1530 VALUES (:username, 'lowspamlevel', :lowspamlevel)");
1531 $stmt->execute(array(
1532 ':username' => $username,
1533 ':lowspamlevel' => $lowspamlevel
1534 ));
1535 $_SESSION['return'][] = array(
1536 'type' => 'success',
1537 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1538 'msg' => array('mailbox_modified', $username)
1539 );
1540 }
1541 break;
1542 case 'time_limited_alias':
1543 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
1544 $_SESSION['return'][] = array(
1545 'type' => 'danger',
1546 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1547 'msg' => 'access_denied'
1548 );
1549 return false;
1550 }
1551 if (!is_array($_data['address'])) {
1552 $addresses = array();
1553 $addresses[] = $_data['address'];
1554 }
1555 else {
1556 $addresses = $_data['address'];
1557 }
1558 foreach ($addresses as $address) {
1559 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
1560 $stmt->execute(array(':address' => $address));
1561 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
1562 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
1563 $_SESSION['return'][] = array(
1564 'type' => 'danger',
1565 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1566 'msg' => 'access_denied'
1567 );
1568 continue;
1569 }
1570 if (empty($_data['validity'])) {
1571 continue;
1572 }
1573 $validity = round((int)time() + ($_data['validity'] * 3600));
1574 $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
1575 `address` = :address");
1576 $stmt->execute(array(
1577 ':address' => $address,
1578 ':validity' => $validity
1579 ));
1580 $_SESSION['return'][] = array(
1581 'type' => 'success',
1582 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001583 'msg' => array('mailbox_modified', htmlspecialchars(implode(', ', (array)$usernames)))
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001584 );
1585 }
1586 break;
1587 case 'delimiter_action':
1588 if (!is_array($_data['username'])) {
1589 $usernames = array();
1590 $usernames[] = $_data['username'];
1591 }
1592 else {
1593 $usernames = $_data['username'];
1594 }
1595 if (!isset($_SESSION['acl']['delimiter_action']) || $_SESSION['acl']['delimiter_action'] != "1" ) {
1596 $_SESSION['return'][] = array(
1597 'type' => 'danger',
1598 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1599 'msg' => 'access_denied'
1600 );
1601 return false;
1602 }
1603 foreach ($usernames as $username) {
1604 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1605 $_SESSION['return'][] = array(
1606 'type' => 'danger',
1607 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1608 'msg' => 'access_denied'
1609 );
1610 continue;
1611 }
1612 if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
1613 try {
1614 $redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
1615 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
1616 }
1617 catch (RedisException $e) {
1618 $_SESSION['return'][] = array(
1619 'type' => 'danger',
1620 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1621 'msg' => array('redis_error', $e)
1622 );
1623 continue;
1624 }
1625 }
1626 else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
1627 try {
1628 $redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
1629 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
1630 }
1631 catch (RedisException $e) {
1632 $_SESSION['return'][] = array(
1633 'type' => 'danger',
1634 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1635 'msg' => array('redis_error', $e)
1636 );
1637 continue;
1638 }
1639 }
1640 else {
1641 try {
1642 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
1643 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
1644 }
1645 catch (RedisException $e) {
1646 $_SESSION['return'][] = array(
1647 'type' => 'danger',
1648 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1649 'msg' => array('redis_error', $e)
1650 );
1651 continue;
1652 }
1653 }
1654 $_SESSION['return'][] = array(
1655 'type' => 'success',
1656 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1657 'msg' => array('mailbox_modified', $username)
1658 );
1659 }
1660 break;
1661 case 'syncjob':
1662 if (!is_array($_data['id'])) {
1663 $ids = array();
1664 $ids[] = $_data['id'];
1665 }
1666 else {
1667 $ids = $_data['id'];
1668 }
1669 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
1670 $_SESSION['return'][] = array(
1671 'type' => 'danger',
1672 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1673 'msg' => 'access_denied'
1674 );
1675 return false;
1676 }
1677 foreach ($ids as $id) {
1678 $is_now = mailbox('get', 'syncjob_details', $id, array('with_password'));
1679 if (!empty($is_now)) {
1680 $username = $is_now['user2'];
1681 $user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1'];
1682 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1683 $last_run = (isset($_data['last_run'])) ? NULL : $is_now['last_run'];
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001684 $success = (isset($_data['success'])) ? NULL : $is_now['success'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001685 $delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
1686 $subscribeall = (isset($_data['subscribeall'])) ? intval($_data['subscribeall']) : $is_now['subscribeall'];
1687 $delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
1688 $delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
1689 $automap = (isset($_data['automap'])) ? intval($_data['automap']) : $is_now['automap'];
1690 $skipcrossduplicates = (isset($_data['skipcrossduplicates'])) ? intval($_data['skipcrossduplicates']) : $is_now['skipcrossduplicates'];
1691 $port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
1692 $password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
1693 $host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
1694 $subfolder2 = (isset($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
1695 $enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
1696 $mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
1697 $exclude = (isset($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
1698 $custom_params = (isset($_data['custom_params'])) ? $_data['custom_params'] : $is_now['custom_params'];
1699 $maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
1700 $maxbytespersecond = (isset($_data['maxbytespersecond']) && $_data['maxbytespersecond'] != "") ? intval($_data['maxbytespersecond']) : $is_now['maxbytespersecond'];
1701 $timeout1 = (isset($_data['timeout1']) && $_data['timeout1'] != "") ? intval($_data['timeout1']) : $is_now['timeout1'];
1702 $timeout2 = (isset($_data['timeout2']) && $_data['timeout2'] != "") ? intval($_data['timeout2']) : $is_now['timeout2'];
1703 }
1704 else {
1705 $_SESSION['return'][] = array(
1706 'type' => 'danger',
1707 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1708 'msg' => 'access_denied'
1709 );
1710 continue;
1711 }
1712 if (strpos($custom_params, 'pipemess')) {
1713 $custom_params = '';
1714 }
1715 if (empty($subfolder2)) {
1716 $subfolder2 = "";
1717 }
1718 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
1719 $maxage = "0";
1720 }
1721 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
1722 $timeout1 = "600";
1723 }
1724 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
1725 $timeout2 = "600";
1726 }
1727 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
1728 $maxbytespersecond = "0";
1729 }
1730 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
1731 $_SESSION['return'][] = array(
1732 'type' => 'danger',
1733 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1734 'msg' => 'access_denied'
1735 );
1736 continue;
1737 }
1738 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
1739 $_SESSION['return'][] = array(
1740 'type' => 'danger',
1741 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1742 'msg' => 'access_denied'
1743 );
1744 continue;
1745 }
1746 if (!is_valid_domain_name($host1)) {
1747 $_SESSION['return'][] = array(
1748 'type' => 'danger',
1749 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1750 'msg' => 'access_denied'
1751 );
1752 continue;
1753 }
1754 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
1755 $_SESSION['return'][] = array(
1756 'type' => 'danger',
1757 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1758 'msg' => 'access_denied'
1759 );
1760 continue;
1761 }
1762 if (@preg_match("/" . $exclude . "/", null) === false) {
1763 $_SESSION['return'][] = array(
1764 'type' => 'danger',
1765 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1766 'msg' => 'access_denied'
1767 );
1768 continue;
1769 }
1770 $stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1,
1771 `delete2` = :delete2,
1772 `automap` = :automap,
1773 `skipcrossduplicates` = :skipcrossduplicates,
1774 `maxage` = :maxage,
1775 `maxbytespersecond` = :maxbytespersecond,
1776 `subfolder2` = :subfolder2,
1777 `exclude` = :exclude,
1778 `host1` = :host1,
1779 `last_run` = :last_run,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001780 `success` = :success,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001781 `user1` = :user1,
1782 `password1` = :password1,
1783 `mins_interval` = :mins_interval,
1784 `port1` = :port1,
1785 `enc1` = :enc1,
1786 `delete2duplicates` = :delete2duplicates,
1787 `custom_params` = :custom_params,
1788 `timeout1` = :timeout1,
1789 `timeout2` = :timeout2,
1790 `subscribeall` = :subscribeall,
1791 `active` = :active
1792 WHERE `id` = :id");
1793 $stmt->execute(array(
1794 ':delete1' => $delete1,
1795 ':delete2' => $delete2,
1796 ':automap' => $automap,
1797 ':skipcrossduplicates' => $skipcrossduplicates,
1798 ':id' => $id,
1799 ':exclude' => $exclude,
1800 ':maxage' => $maxage,
1801 ':maxbytespersecond' => $maxbytespersecond,
1802 ':subfolder2' => $subfolder2,
1803 ':host1' => $host1,
1804 ':user1' => $user1,
1805 ':password1' => $password1,
1806 ':last_run' => $last_run,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001807 ':success' => $success,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001808 ':mins_interval' => $mins_interval,
1809 ':port1' => $port1,
1810 ':enc1' => $enc1,
1811 ':delete2duplicates' => $delete2duplicates,
1812 ':custom_params' => $custom_params,
1813 ':timeout1' => $timeout1,
1814 ':timeout2' => $timeout2,
1815 ':subscribeall' => $subscribeall,
1816 ':active' => $active,
1817 ));
1818 $_SESSION['return'][] = array(
1819 'type' => 'success',
1820 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1821 'msg' => array('mailbox_modified', $username)
1822 );
1823 }
1824 break;
1825 case 'filter':
1826 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
1827 $_SESSION['return'][] = array(
1828 'type' => 'danger',
1829 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1830 'msg' => 'access_denied'
1831 );
1832 return false;
1833 }
1834 $sieve = new Sieve\SieveParser();
1835 if (!is_array($_data['id'])) {
1836 $ids = array();
1837 $ids[] = $_data['id'];
1838 }
1839 else {
1840 $ids = $_data['id'];
1841 }
1842 foreach ($ids as $id) {
1843 $is_now = mailbox('get', 'filter_details', $id);
1844 if (!empty($is_now)) {
1845 $username = $is_now['username'];
1846 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1847 $script_desc = (!empty($_data['script_desc'])) ? $_data['script_desc'] : $is_now['script_desc'];
1848 $script_data = (!empty($_data['script_data'])) ? $_data['script_data'] : $is_now['script_data'];
1849 $filter_type = (!empty($_data['filter_type'])) ? $_data['filter_type'] : $is_now['filter_type'];
1850 }
1851 else {
1852 $_SESSION['return'][] = array(
1853 'type' => 'danger',
1854 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1855 'msg' => 'access_denied'
1856 );
1857 continue;
1858 }
1859 try {
1860 $sieve->parse($script_data);
1861 }
1862 catch (Exception $e) {
1863 $_SESSION['return'][] = array(
1864 'type' => 'danger',
1865 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1866 'msg' => array('sieve_error', $e->getMessage())
1867 );
1868 continue;
1869 }
1870 if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
1871 $_SESSION['return'][] = array(
1872 'type' => 'danger',
1873 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1874 'msg' => 'filter_type'
1875 );
1876 continue;
1877 }
1878 if ($active == '1') {
1879 $script_name = 'active';
1880 $stmt = $pdo->prepare("UPDATE `sieve_filters`
1881 SET `script_name` = 'inactive'
1882 WHERE `username` = :username
1883 AND `filter_type` = :filter_type");
1884 $stmt->execute(array(
1885 ':username' => $username,
1886 ':filter_type' => $filter_type
1887 ));
1888 }
1889 else {
1890 $script_name = 'inactive';
1891 }
1892 $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_desc` = :script_desc, `script_data` = :script_data, `script_name` = :script_name, `filter_type` = :filter_type
1893 WHERE `id` = :id");
1894 $stmt->execute(array(
1895 ':script_desc' => $script_desc,
1896 ':script_data' => $script_data,
1897 ':script_name' => $script_name,
1898 ':filter_type' => $filter_type,
1899 ':id' => $id
1900 ));
1901 $_SESSION['return'][] = array(
1902 'type' => 'success',
1903 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1904 'msg' => array('mailbox_modified', $username)
1905 );
1906 }
1907 break;
1908 case 'alias':
1909 if (!is_array($_data['id'])) {
1910 $ids = array();
1911 $ids[] = $_data['id'];
1912 }
1913 else {
1914 $ids = $_data['id'];
1915 }
1916 foreach ($ids as $id) {
1917 $is_now = mailbox('get', 'alias_details', $id);
1918 if (!empty($is_now)) {
1919 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1920 $sogo_visible = (isset($_data['sogo_visible'])) ? intval($_data['sogo_visible']) : $is_now['sogo_visible'];
1921 $goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
1922 $goto_spam = (isset($_data['goto_spam'])) ? intval($_data['goto_spam']) : 0;
1923 $goto_ham = (isset($_data['goto_ham'])) ? intval($_data['goto_ham']) : 0;
1924 $public_comment = (isset($_data['public_comment'])) ? $_data['public_comment'] : $is_now['public_comment'];
1925 $private_comment = (isset($_data['private_comment'])) ? $_data['private_comment'] : $is_now['private_comment'];
1926 $goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
1927 $address = (!empty($_data['address'])) ? $_data['address'] : $is_now['address'];
1928 }
1929 else {
1930 $_SESSION['return'][] = array(
1931 'type' => 'danger',
1932 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1933 'msg' => array('alias_invalid', $address)
1934 );
1935 continue;
1936 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001937 if ($_data['expand_alias'] === true || $_data['expand_alias'] == 1) {
1938 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
1939 WHERE `address` = :address
1940 AND `domain` NOT IN (
1941 SELECT `alias_domain` FROM `alias_domain`
1942 )");
1943 $stmt->execute(array(
1944 ':address' => $address,
1945 ));
1946 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1947 if ($num_results == 0) {
1948 $_SESSION['return'][] = array(
1949 'type' => 'warning',
1950 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1951 'msg' => array('is_not_primary_alias', htmlspecialchars($address))
1952 );
1953 continue;
1954 }
1955 $stmt = $pdo->prepare("SELECT `goto`, GROUP_CONCAT(CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`)) AS `missing_alias`
1956 FROM `alias` JOIN `alias_domain` ON `alias_domain`.`target_domain` = `alias`.`domain`
1957 WHERE CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`) NOT IN (
1958 SELECT `address` FROM `alias` WHERE `address` != `goto`
1959 )
1960 AND `alias`.`address` NOT IN (
1961 SELECT `address` FROM `alias` WHERE `address` = `goto`
1962 )
1963 AND `address` = :address ;");
1964 $stmt->execute(array(
1965 ':address' => $address
1966 ));
1967 $missing_aliases = $stmt->fetch(PDO::FETCH_ASSOC);
1968 if (!empty($missing_aliases['missing_alias'])) {
1969 mailbox('add', 'alias', array(
1970 'address' => $missing_aliases['missing_alias'],
1971 'goto' => $missing_aliases['goto'],
1972 'sogo_visible' => 1,
1973 'active' => 1
1974 ));
1975 }
1976 $_SESSION['return'][] = array(
1977 'type' => 'success',
1978 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1979 'msg' => array('alias_modified', htmlspecialchars($address))
1980 );
1981 continue;
1982 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001983 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
1984 if ($is_now['address'] != $address) {
1985 $local_part = strstr($address, '@', true);
1986 $address = $local_part.'@'.$domain;
1987 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1988 $_SESSION['return'][] = array(
1989 'type' => 'danger',
1990 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1991 'msg' => 'access_denied'
1992 );
1993 continue;
1994 }
1995 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
1996 $_SESSION['return'][] = array(
1997 'type' => 'danger',
1998 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1999 'msg' => array('alias_invalid', $address)
2000 );
2001 continue;
2002 }
2003 if (strtolower($is_now['address']) != strtolower($address)) {
2004 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2005 WHERE `address`= :address OR `address` IN (
2006 SELECT `username` FROM `mailbox`, `alias_domain`
2007 WHERE (
2008 `alias_domain`.`alias_domain` = :address_d
2009 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
2010 $stmt->execute(array(
2011 ':address' => $address,
2012 ':address_l' => $local_part,
2013 ':address_d' => $domain
2014 ));
2015 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2016 if ($num_results != 0) {
2017 $_SESSION['return'][] = array(
2018 'type' => 'danger',
2019 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2020 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
2021 );
2022 continue;
2023 }
2024 }
2025 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
2026 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
2027 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
2028 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2029 if ($num_results == 0) {
2030 $_SESSION['return'][] = array(
2031 'type' => 'danger',
2032 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2033 'msg' => array('domain_not_found', htmlspecialchars($domain))
2034 );
2035 continue;
2036 }
2037 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
2038 WHERE `address`= :address");
2039 $stmt->execute(array(':address' => $address));
2040 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2041 if ($num_results != 0) {
2042 $_SESSION['return'][] = array(
2043 'type' => 'danger',
2044 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2045 'msg' => array('is_spam_alias', htmlspecialchars($address))
2046 );
2047 continue;
2048 }
2049 }
2050 if ($goto_null == "1") {
2051 $goto = "null@localhost";
2052 }
2053 elseif ($goto_spam == "1") {
2054 $goto = "spam@localhost";
2055 }
2056 elseif ($goto_ham == "1") {
2057 $goto = "ham@localhost";
2058 }
2059 else {
2060 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $goto));
2061 foreach ($gotos as $i => &$goto) {
2062 if (empty($goto)) {
2063 continue;
2064 }
2065 if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) {
2066 $_SESSION['return'][] = array(
2067 'type' => 'danger',
2068 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2069 'msg' => array('goto_invalid', $goto)
2070 );
2071 unset($gotos[$i]);
2072 continue;
2073 }
2074 if ($goto == $address) {
2075 $_SESSION['return'][] = array(
2076 'type' => 'danger',
2077 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2078 'msg' => 'alias_goto_identical'
2079 );
2080 unset($gotos[$i]);
2081 continue;
2082 }
2083 // Delete from sender_acl to prevent duplicates
2084 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE
2085 `logged_in_as` = :goto AND
2086 `send_as` = :address");
2087 $stmt->execute(array(
2088 ':goto' => $goto,
2089 ':address' => $address
2090 ));
2091 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002092 $gotos = array_unique($gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002093 $gotos = array_filter($gotos);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002094 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002095 }
2096 if (!empty($goto)) {
2097 $stmt = $pdo->prepare("UPDATE `alias` SET
2098 `address` = :address,
2099 `public_comment` = :public_comment,
2100 `private_comment` = :private_comment,
2101 `domain` = :domain,
2102 `goto` = :goto,
2103 `sogo_visible`= :sogo_visible,
2104 `active`= :active
2105 WHERE `id` = :id");
2106 $stmt->execute(array(
2107 ':address' => $address,
2108 ':public_comment' => $public_comment,
2109 ':private_comment' => $private_comment,
2110 ':domain' => $domain,
2111 ':goto' => $goto,
2112 ':sogo_visible' => $sogo_visible,
2113 ':active' => $active,
2114 ':id' => $is_now['id']
2115 ));
2116 }
2117 $_SESSION['return'][] = array(
2118 'type' => 'success',
2119 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2120 'msg' => array('alias_modified', htmlspecialchars($address))
2121 );
2122 }
2123 break;
2124 case 'domain':
2125 if (!is_array($_data['domain'])) {
2126 $domains = array();
2127 $domains[] = $_data['domain'];
2128 }
2129 else {
2130 $domains = $_data['domain'];
2131 }
2132 foreach ($domains as $domain) {
2133 $domain = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
2134 if (!is_valid_domain_name($domain)) {
2135 $_SESSION['return'][] = array(
2136 'type' => 'danger',
2137 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2138 'msg' => 'domain_invalid'
2139 );
2140 continue;
2141 }
2142 if ($_SESSION['mailcow_cc_role'] == "domainadmin" &&
2143 hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2144 $is_now = mailbox('get', 'domain_details', $domain);
2145 if (!empty($is_now)) {
2146 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2147 $description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002148 (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002149 }
2150 else {
2151 $_SESSION['return'][] = array(
2152 'type' => 'danger',
2153 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2154 'msg' => 'domain_invalid'
2155 );
2156 continue;
2157 }
2158 $stmt = $pdo->prepare("UPDATE `domain` SET
2159 `description` = :description,
2160 `gal` = :gal
2161 WHERE `domain` = :domain");
2162 $stmt->execute(array(
2163 ':description' => $description,
2164 ':gal' => $gal,
2165 ':domain' => $domain
2166 ));
2167 $_SESSION['return'][] = array(
2168 'type' => 'success',
2169 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2170 'msg' => array('domain_modified', htmlspecialchars($domain))
2171 );
2172 }
2173 elseif ($_SESSION['mailcow_cc_role'] == "admin") {
2174 $is_now = mailbox('get', 'domain_details', $domain);
2175 if (!empty($is_now)) {
2176 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2177 $backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx'];
2178 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2179 $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients'];
2180 $relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $is_now['relay_unknown_only'];
2181 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : $is_now['relayhost'];
2182 $aliases = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain'];
2183 $mailboxes = (isset($_data['mailboxes']) && $_data['mailboxes'] != '') ? intval($_data['mailboxes']) : $is_now['max_num_mboxes_for_domain'];
2184 $defquota = (isset($_data['defquota']) && $_data['defquota'] != '') ? intval($_data['defquota']) : ($is_now['def_quota_for_mbox'] / 1048576);
2185 $maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
2186 $quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
2187 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
2188 if ($relay_all_recipients == '1') {
2189 $backupmx = '1';
2190 }
2191 if ($relay_unknown_only == '1') {
2192 $backupmx = '1';
2193 $relay_all_recipients = '1';
2194 }
2195 }
2196 else {
2197 $_SESSION['return'][] = array(
2198 'type' => 'danger',
2199 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2200 'msg' => 'domain_invalid'
2201 );
2202 continue;
2203 }
2204 // todo: should be using api here
2205 $stmt = $pdo->prepare("SELECT
2206 COUNT(*) AS count,
2207 MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
2208 COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
2209 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002210 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002211 AND domain = :domain");
2212 $stmt->execute(array(':domain' => $domain));
2213 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
2214 // todo: should be using api here
2215 $stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
2216 WHERE domain = :domain
2217 AND address NOT IN (
2218 SELECT `username` FROM `mailbox`
2219 )");
2220 $stmt->execute(array(':domain' => $domain));
2221 $AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
2222 if ($defquota > $maxquota) {
2223 $_SESSION['return'][] = array(
2224 'type' => 'danger',
2225 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2226 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
2227 );
2228 continue;
2229 }
2230 if ($defquota == "0" || empty($defquota)) {
2231 $_SESSION['return'][] = array(
2232 'type' => 'danger',
2233 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2234 'msg' => 'defquota_empty'
2235 );
2236 continue;
2237 }
2238 if ($maxquota > $quota) {
2239 $_SESSION['return'][] = array(
2240 'type' => 'danger',
2241 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2242 'msg' => 'mailbox_quota_exceeds_domain_quota'
2243 );
2244 continue;
2245 }
2246 if ($maxquota == "0" || empty($maxquota)) {
2247 $_SESSION['return'][] = array(
2248 'type' => 'danger',
2249 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2250 'msg' => 'maxquota_empty'
2251 );
2252 continue;
2253 }
2254 if ($MailboxData['biggest_mailbox'] > $maxquota) {
2255 $_SESSION['return'][] = array(
2256 'type' => 'danger',
2257 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2258 'msg' => array('max_quota_in_use', $MailboxData['biggest_mailbox'])
2259 );
2260 continue;
2261 }
2262 if ($MailboxData['quota_all'] > $quota) {
2263 $_SESSION['return'][] = array(
2264 'type' => 'danger',
2265 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2266 'msg' => array('domain_quota_m_in_use', $MailboxData['quota_all'])
2267 );
2268 continue;
2269 }
2270 if ($MailboxData['count'] > $mailboxes) {
2271 $_SESSION['return'][] = array(
2272 'type' => 'danger',
2273 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2274 'msg' => array('mailboxes_in_use', $MailboxData['count'])
2275 );
2276 continue;
2277 }
2278 if ($AliasData['count'] > $aliases) {
2279 $_SESSION['return'][] = array(
2280 'type' => 'danger',
2281 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2282 'msg' => array('aliases_in_use', $AliasData['count'])
2283 );
2284 continue;
2285 }
2286 $stmt = $pdo->prepare("UPDATE `domain` SET
2287 `relay_all_recipients` = :relay_all_recipients,
2288 `relay_unknown_only` = :relay_unknown_only,
2289 `backupmx` = :backupmx,
2290 `gal` = :gal,
2291 `active` = :active,
2292 `quota` = :quota,
2293 `defquota` = :defquota,
2294 `maxquota` = :maxquota,
2295 `relayhost` = :relayhost,
2296 `mailboxes` = :mailboxes,
2297 `aliases` = :aliases,
2298 `description` = :description
2299 WHERE `domain` = :domain");
2300 $stmt->execute(array(
2301 ':relay_all_recipients' => $relay_all_recipients,
2302 ':relay_unknown_only' => $relay_unknown_only,
2303 ':backupmx' => $backupmx,
2304 ':gal' => $gal,
2305 ':active' => $active,
2306 ':quota' => $quota,
2307 ':defquota' => $defquota,
2308 ':maxquota' => $maxquota,
2309 ':relayhost' => $relayhost,
2310 ':mailboxes' => $mailboxes,
2311 ':aliases' => $aliases,
2312 ':description' => $description,
2313 ':domain' => $domain
2314 ));
2315 $_SESSION['return'][] = array(
2316 'type' => 'success',
2317 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2318 'msg' => array('domain_modified', htmlspecialchars($domain))
2319 );
2320 }
2321 }
2322 break;
2323 case 'mailbox':
2324 if (!is_array($_data['username'])) {
2325 $usernames = array();
2326 $usernames[] = $_data['username'];
2327 }
2328 else {
2329 $usernames = $_data['username'];
2330 }
2331 foreach ($usernames as $username) {
2332 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
2333 $_SESSION['return'][] = array(
2334 'type' => 'danger',
2335 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2336 'msg' => array('username_invalid', $username)
2337 );
2338 continue;
2339 }
2340 $is_now = mailbox('get', 'mailbox_details', $username);
2341 if (isset($_data['protocol_access'])) {
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002342 $_data['protocol_access'] = (array)$_data['protocol_access'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002343 $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
2344 $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
2345 $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002346 $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002347 }
2348 if (!empty($is_now)) {
2349 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2350 (int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']);
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002351 (int)$sogo_access = (isset($_data['sogo_access']) && isset($_SESSION['acl']['sogo_access']) && $_SESSION['acl']['sogo_access'] == "1") ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002352 (int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
2353 (int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
2354 (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002355 (int)$sieve_access = (isset($_data['sieve_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002356 (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002357 (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
2358 $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
2359 $domain = $is_now['domain'];
2360 $quota_b = $quota_m * 1048576;
2361 $password = (!empty($_data['password'])) ? $_data['password'] : null;
2362 $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
2363 }
2364 else {
2365 $_SESSION['return'][] = array(
2366 'type' => 'danger',
2367 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2368 'msg' => 'access_denied'
2369 );
2370 continue;
2371 }
2372 // if already 0 == ok
2373 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && ($quota_m == 0 && $is_now['quota'] != 0)) {
2374 $_SESSION['return'][] = array(
2375 'type' => 'danger',
2376 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2377 'msg' => 'unlimited_quota_acl'
2378 );
2379 return false;
2380 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002381 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2382 $_SESSION['return'][] = array(
2383 'type' => 'danger',
2384 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2385 'msg' => 'access_denied'
2386 );
2387 continue;
2388 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002389 $DomainData = mailbox('get', 'domain_details', $domain);
2390 if ($quota_m > ($is_now['max_new_quota'] / 1048576)) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002391 $_SESSION['return'][] = array(
2392 'type' => 'danger',
2393 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2394 'msg' => array('mailbox_quota_left_exceeded', ($is_now['max_new_quota'] / 1048576))
2395 );
2396 continue;
2397 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002398 if ($quota_m > $DomainData['max_quota_for_mbox']) {
2399 $_SESSION['return'][] = array(
2400 'type' => 'danger',
2401 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2402 'msg' => array('mailbox_quota_exceeded', $DomainData['max_quota_for_mbox'])
2403 );
2404 continue;
2405 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002406 $extra_acls = array();
2407 if (isset($_data['extended_sender_acl'])) {
2408 if (!isset($_SESSION['acl']['extend_sender_acl']) || $_SESSION['acl']['extend_sender_acl'] != "1" ) {
2409 $_SESSION['return'][] = array(
2410 'type' => 'danger',
2411 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2412 'msg' => 'access_denied'
2413 );
2414 return false;
2415 }
2416 $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
2417 foreach ($extra_acls as $i => &$extra_acl) {
2418 if (empty($extra_acl)) {
2419 continue;
2420 }
2421 if (substr($extra_acl, 0, 1) === "@") {
2422 $extra_acl = ltrim($extra_acl, '@');
2423 }
2424 if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
2425 $_SESSION['return'][] = array(
2426 'type' => 'danger',
2427 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2428 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
2429 );
2430 unset($extra_acls[$i]);
2431 continue;
2432 }
2433 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
2434 if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
2435 $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2436 if (in_array($extra_acl_domain, $domains)) {
2437 $_SESSION['return'][] = array(
2438 'type' => 'danger',
2439 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2440 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2441 );
2442 unset($extra_acls[$i]);
2443 continue;
2444 }
2445 }
2446 else {
2447 if (in_array($extra_acl, $domains)) {
2448 $_SESSION['return'][] = array(
2449 'type' => 'danger',
2450 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2451 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2452 );
2453 unset($extra_acls[$i]);
2454 continue;
2455 }
2456 $extra_acl = '@' . $extra_acl;
2457 }
2458 }
2459 $extra_acls = array_filter($extra_acls);
2460 $extra_acls = array_values($extra_acls);
2461 $extra_acls = array_unique($extra_acls);
2462 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
2463 $stmt->execute(array(
2464 ':username' => $username
2465 ));
2466 foreach ($extra_acls as $sender_acl_external) {
2467 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
2468 VALUES (:sender_acl, :username, 1)");
2469 $stmt->execute(array(
2470 ':sender_acl' => $sender_acl_external,
2471 ':username' => $username
2472 ));
2473 }
2474 }
2475 if (isset($_data['sender_acl'])) {
2476 // Get sender_acl items set by admin
2477 $sender_acl_admin = array_merge(
2478 mailbox('get', 'sender_acl_handles', $username)['sender_acl_domains']['ro'],
2479 mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro']
2480 );
2481 // Get sender_acl items from POST array
2482 // Set sender_acl_domain_admin to empty array if sender_acl contains "default" to trigger a reset
2483 // Delete records from sender_acl if sender_acl contains "*" and set to array("*")
2484 $_data['sender_acl'] = (array)$_data['sender_acl'];
2485 if (in_array("*", $_data['sender_acl'])) {
2486 $sender_acl_domain_admin = array('*');
2487 }
2488 elseif (array("default") === $_data['sender_acl']) {
2489 $sender_acl_domain_admin = array();
2490 }
2491 else {
2492 if (array_search('default', $_data['sender_acl']) !== false){
2493 unset($_data['sender_acl'][array_search('default', $_data['sender_acl'])]);
2494 }
2495 $sender_acl_domain_admin = $_data['sender_acl'];
2496 }
2497 if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) {
2498 // Check items in POST array and skip invalid
2499 foreach ($sender_acl_domain_admin as $key => $val) {
2500 // Check for invalid domain or email format or not *
2501 if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@')) && $val != '*') {
2502 $_SESSION['return'][] = array(
2503 'type' => 'danger',
2504 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2505 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2506 );
2507 unset($sender_acl_domain_admin[$key]);
2508 continue;
2509 }
2510 // Check if user has domain access (if object is domain)
2511 $domain = ltrim($sender_acl_domain_admin[$key], '@');
2512 if (is_valid_domain_name($domain)) {
2513 // Check for- and skip non-mailcow domains
2514 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
2515 if (!empty($domains)) {
2516 if (!in_array($domain, $domains)) {
2517 $_SESSION['return'][] = array(
2518 'type' => 'danger',
2519 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2520 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2521 );
2522 unset($sender_acl_domain_admin[$key]);
2523 continue;
2524 }
2525 }
2526 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2527 $_SESSION['return'][] = array(
2528 'type' => 'danger',
2529 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2530 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2531 );
2532 unset($sender_acl_domain_admin[$key]);
2533 continue;
2534 }
2535 }
2536 // Wildcard can only be used if role == admin
2537 if ($val == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
2538 $_SESSION['return'][] = array(
2539 'type' => 'danger',
2540 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2541 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2542 );
2543 unset($sender_acl_domain_admin[$key]);
2544 continue;
2545 }
2546 // Check if user has alias access (if object is email)
2547 if (filter_var($val, FILTER_VALIDATE_EMAIL)) {
2548 if (!hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) {
2549 $_SESSION['return'][] = array(
2550 'type' => 'danger',
2551 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2552 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2553 );
2554 unset($sender_acl_domain_admin[$key]);
2555 continue;
2556 }
2557 }
2558 }
2559 // Merge both arrays
2560 $sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin);
2561 // If merged array still contains "*", set it as only value
2562 !in_array('*', $sender_acl_merged) ?: $sender_acl_merged = array('*');
2563 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
2564 $stmt->execute(array(
2565 ':username' => $username
2566 ));
2567 $fixed_sender_aliases = mailbox('get', 'sender_acl_handles', $username)['fixed_sender_aliases'];
2568 foreach ($sender_acl_merged as $sender_acl) {
2569 $domain = ltrim($sender_acl, '@');
2570 if (is_valid_domain_name($domain)) {
2571 $sender_acl = '@' . $domain;
2572 }
2573 // Don't add if allowed by alias
2574 if (in_array($sender_acl, $fixed_sender_aliases)) {
2575 continue;
2576 }
2577 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`)
2578 VALUES (:sender_acl, :username)");
2579 $stmt->execute(array(
2580 ':sender_acl' => $sender_acl,
2581 ':username' => $username
2582 ));
2583 }
2584 }
2585 else {
2586 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
2587 $stmt->execute(array(
2588 ':username' => $username
2589 ));
2590 }
2591 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002592 if (!empty($password)) {
2593 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002594 continue;
2595 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002596 $password_hashed = hash_password($password);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002597 $stmt = $pdo->prepare("UPDATE `mailbox` SET
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002598 `password` = :password_hashed,
2599 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002600 WHERE `username` = :username");
2601 $stmt->execute(array(
2602 ':password_hashed' => $password_hashed,
2603 ':username' => $username
2604 ));
2605 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002606 // We could either set alias = 1 if alias = 2 or tune the Postfix alias table (that's what we did, TODO: do it the other way)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002607 $stmt = $pdo->prepare("UPDATE `alias` SET
2608 `active` = :active
2609 WHERE `address` = :address");
2610 $stmt->execute(array(
2611 ':address' => $username,
2612 ':active' => $active
2613 ));
2614 $stmt = $pdo->prepare("UPDATE `mailbox` SET
2615 `active` = :active,
2616 `name`= :name,
2617 `quota` = :quota_b,
2618 `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
2619 `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
2620 `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002621 `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002622 `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002623 `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002624 `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access)
2625 WHERE `username` = :username");
2626 $stmt->execute(array(
2627 ':active' => $active,
2628 ':name' => $name,
2629 ':quota_b' => $quota_b,
2630 ':force_pw_update' => $force_pw_update,
2631 ':sogo_access' => $sogo_access,
2632 ':imap_access' => $imap_access,
2633 ':pop3_access' => $pop3_access,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002634 ':sieve_access' => $sieve_access,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002635 ':smtp_access' => $smtp_access,
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002636 ':relayhost' => $relayhost,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002637 ':username' => $username
2638 ));
2639 $_SESSION['return'][] = array(
2640 'type' => 'success',
2641 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2642 'msg' => array('mailbox_modified', $username)
2643 );
2644 }
2645 break;
2646 case 'resource':
2647 if (!is_array($_data['name'])) {
2648 $names = array();
2649 $names[] = $_data['name'];
2650 }
2651 else {
2652 $names = $_data['name'];
2653 }
2654 foreach ($names as $name) {
2655 $is_now = mailbox('get', 'resource_details', $name);
2656 if (!empty($is_now)) {
2657 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2658 $multiple_bookings = (isset($_data['multiple_bookings'])) ? intval($_data['multiple_bookings']) : $is_now['multiple_bookings'];
2659 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
2660 $kind = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind'];
2661 }
2662 else {
2663 $_SESSION['return'][] = array(
2664 'type' => 'danger',
2665 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2666 'msg' => array('resource_invalid', htmlspecialchars($name))
2667 );
2668 continue;
2669 }
2670 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
2671 $_SESSION['return'][] = array(
2672 'type' => 'danger',
2673 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2674 'msg' => array('resource_invalid', htmlspecialchars($name))
2675 );
2676 continue;
2677 }
2678 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
2679 $multiple_bookings = -1;
2680 }
2681 if (empty($description)) {
2682 $_SESSION['return'][] = array(
2683 'type' => 'danger',
2684 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2685 'msg' => array('description_invalid', htmlspecialchars($name))
2686 );
2687 continue;
2688 }
2689 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
2690 $_SESSION['return'][] = array(
2691 'type' => 'danger',
2692 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2693 'msg' => array('resource_invalid', htmlspecialchars($name))
2694 );
2695 continue;
2696 }
2697 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
2698 $_SESSION['return'][] = array(
2699 'type' => 'danger',
2700 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2701 'msg' => 'access_denied'
2702 );
2703 continue;
2704 }
2705 $stmt = $pdo->prepare("UPDATE `mailbox` SET
2706 `active` = :active,
2707 `name`= :description,
2708 `kind`= :kind,
2709 `multiple_bookings`= :multiple_bookings
2710 WHERE `username` = :name");
2711 $stmt->execute(array(
2712 ':active' => $active,
2713 ':description' => $description,
2714 ':multiple_bookings' => $multiple_bookings,
2715 ':kind' => $kind,
2716 ':name' => $name
2717 ));
2718 $_SESSION['return'][] = array(
2719 'type' => 'success',
2720 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2721 'msg' => array('resource_modified', htmlspecialchars($name))
2722 );
2723 }
2724 break;
2725 }
2726 break;
2727 case 'get':
2728 switch ($_type) {
2729 case 'sender_acl_handles':
2730 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
2731 return false;
2732 }
2733 $data['sender_acl_domains']['ro'] = array();
2734 $data['sender_acl_domains']['rw'] = array();
2735 $data['sender_acl_domains']['selectable'] = array();
2736 $data['sender_acl_addresses']['ro'] = array();
2737 $data['sender_acl_addresses']['rw'] = array();
2738 $data['sender_acl_addresses']['selectable'] = array();
2739 $data['fixed_sender_aliases'] = array();
2740 $data['external_sender_aliases'] = array();
2741 // Fixed addresses
2742 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
2743 $stmt->execute(array(':goto' => '(^|,)'.$_data.'($|,)'));
2744 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2745 while ($row = array_shift($rows)) {
2746 $data['fixed_sender_aliases'][] = $row['address'];
2747 }
2748 $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias_domain_alias` FROM `mailbox`, `alias_domain`
2749 WHERE `alias_domain`.`target_domain` = `mailbox`.`domain`
2750 AND `mailbox`.`username` = :username");
2751 $stmt->execute(array(':username' => $_data));
2752 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2753 while ($row = array_shift($rows)) {
2754 if (!empty($row['alias_domain_alias'])) {
2755 $data['fixed_sender_aliases'][] = $row['alias_domain_alias'];
2756 }
2757 }
2758 // External addresses
2759 $stmt = $pdo->prepare("SELECT `send_as` as `send_as_external` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '1'");
2760 $stmt->execute(array(':logged_in_as' => $_data));
2761 $exernal_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2762 while ($row = array_shift($exernal_rows)) {
2763 if (!empty($row['send_as_external'])) {
2764 $data['external_sender_aliases'][] = $row['send_as_external'];
2765 }
2766 }
2767 // Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects
2768 // Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted)
2769 $stmt = $pdo->prepare("SELECT REPLACE(`send_as`, '@', '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '0' AND (`send_as` LIKE '@%' OR `send_as` = '*')");
2770 $stmt->execute(array(':logged_in_as' => $_data));
2771 $domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2772 while ($domain_row = array_shift($domain_rows)) {
2773 if (is_valid_domain_name($domain_row['send_as']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
2774 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
2775 continue;
2776 }
2777 if (is_valid_domain_name($domain_row['send_as']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
2778 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
2779 continue;
2780 }
2781 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
2782 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
2783 }
2784 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
2785 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
2786 }
2787 }
2788 $stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '0' AND (`send_as` NOT LIKE '@%' AND `send_as` != '*')");
2789 $stmt->execute(array(':logged_in_as' => $_data));
2790 $address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2791 while ($address_row = array_shift($address_rows)) {
2792 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
2793 $data['sender_acl_addresses']['ro'][] = $address_row['send_as'];
2794 continue;
2795 }
2796 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
2797 $data['sender_acl_addresses']['rw'][] = $address_row['send_as'];
2798 continue;
2799 }
2800 }
2801 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
2802 WHERE `domain` NOT IN (
2803 SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl`
2804 WHERE `logged_in_as` = :logged_in_as1
2805 AND `external` = '0'
2806 AND `send_as` LIKE '@%')
2807 UNION
2808 SELECT '*' FROM `domain`
2809 WHERE '*' NOT IN (
2810 SELECT `send_as` FROM `sender_acl`
2811 WHERE `logged_in_as` = :logged_in_as2
2812 AND `external` = '0'
2813 )");
2814 $stmt->execute(array(
2815 ':logged_in_as1' => $_data,
2816 ':logged_in_as2' => $_data
2817 ));
2818 $rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
2819 while ($row_domain = array_shift($rows_domain)) {
2820 if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) {
2821 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
2822 continue;
2823 }
2824 if ($row_domain['domain'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
2825 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
2826 continue;
2827 }
2828 }
2829 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2830 WHERE `goto` != :goto
2831 AND `address` NOT IN (
2832 SELECT `send_as` FROM `sender_acl`
2833 WHERE `logged_in_as` = :logged_in_as
2834 AND `external` = '0'
2835 AND `send_as` NOT LIKE '@%')");
2836 $stmt->execute(array(
2837 ':logged_in_as' => $_data,
2838 ':goto' => $_data
2839 ));
2840 $rows_mbox = $stmt->fetchAll(PDO::FETCH_ASSOC);
2841 while ($row = array_shift($rows_mbox)) {
2842 // Aliases are not selectable
2843 if (in_array($row['address'], $data['fixed_sender_aliases'])) {
2844 continue;
2845 }
2846 if (filter_var($row['address'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['address'])) {
2847 $data['sender_acl_addresses']['selectable'][] = $row['address'];
2848 }
2849 }
2850 return $data;
2851 break;
2852 case 'mailboxes':
2853 $mailboxes = array();
2854 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2855 return false;
2856 }
2857 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002858 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002859 $stmt->execute(array(
2860 ':domain' => $_data,
2861 ));
2862 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2863 while($row = array_shift($rows)) {
2864 $mailboxes[] = $row['username'];
2865 }
2866 }
2867 else {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002868 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND (`domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role)");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002869 $stmt->execute(array(
2870 ':username' => $_SESSION['mailcow_cc_username'],
2871 ':role' => $_SESSION['mailcow_cc_role'],
2872 ));
2873 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2874 while($row = array_shift($rows)) {
2875 $mailboxes[] = $row['username'];
2876 }
2877 }
2878 return $mailboxes;
2879 break;
2880 case 'tls_policy':
2881 $attrs = array();
2882 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
2883 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2884 return false;
2885 }
2886 }
2887 else {
2888 $_data = $_SESSION['mailcow_cc_username'];
2889 }
2890 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
2891 $stmt->execute(array(':username' => $_data));
2892 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
2893 $attrs = json_decode($attrs['attributes'], true);
2894 return array(
2895 'tls_enforce_in' => $attrs['tls_enforce_in'],
2896 'tls_enforce_out' => $attrs['tls_enforce_out']
2897 );
2898 break;
2899 case 'quarantine_notification':
2900 $attrs = array();
2901 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
2902 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2903 return false;
2904 }
2905 }
2906 else {
2907 $_data = $_SESSION['mailcow_cc_username'];
2908 }
2909 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
2910 $stmt->execute(array(':username' => $_data));
2911 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
2912 $attrs = json_decode($attrs['attributes'], true);
2913 return $attrs['quarantine_notification'];
2914 break;
2915 case 'quarantine_category':
2916 $attrs = array();
2917 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
2918 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2919 return false;
2920 }
2921 }
2922 else {
2923 $_data = $_SESSION['mailcow_cc_username'];
2924 }
2925 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
2926 $stmt->execute(array(':username' => $_data));
2927 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
2928 $attrs = json_decode($attrs['attributes'], true);
2929 return $attrs['quarantine_category'];
2930 break;
2931 case 'filters':
2932 $filters = array();
2933 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
2934 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2935 return false;
2936 }
2937 }
2938 else {
2939 $_data = $_SESSION['mailcow_cc_username'];
2940 }
2941 $stmt = $pdo->prepare("SELECT `id` FROM `sieve_filters` WHERE `username` = :username");
2942 $stmt->execute(array(':username' => $_data));
2943 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
2944 while($row = array_shift($rows)) {
2945 $filters[] = $row['id'];
2946 }
2947 return $filters;
2948 break;
2949 case 'global_filter_details':
2950 $global_filters = array();
2951 if ($_SESSION['mailcow_cc_role'] != "admin") {
2952 return false;
2953 }
2954 $global_filters['prefilter'] = file_get_contents('/global_sieve/before');
2955 $global_filters['postfilter'] = file_get_contents('/global_sieve/after');
2956 return $global_filters;
2957 break;
2958 case 'filter_details':
2959 $filter_details = array();
2960 if (!is_numeric($_data)) {
2961 return false;
2962 }
2963 $stmt = $pdo->prepare("SELECT CASE `script_name` WHEN 'active' THEN 1 ELSE 0 END AS `active`,
2964 id,
2965 username,
2966 filter_type,
2967 script_data,
2968 script_desc
2969 FROM `sieve_filters`
2970 WHERE `id` = :id");
2971 $stmt->execute(array(':id' => $_data));
2972 $filter_details = $stmt->fetch(PDO::FETCH_ASSOC);
2973 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $filter_details['username'])) {
2974 return false;
2975 }
2976 return $filter_details;
2977 break;
2978 case 'active_user_sieve':
2979 $filter_details = array();
2980 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
2981 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
2982 return false;
2983 }
2984 }
2985 else {
2986 $_data = $_SESSION['mailcow_cc_username'];
2987 }
2988 $exec_fields = array(
2989 'cmd' => 'sieve',
2990 'task' => 'list',
2991 'username' => $_data
2992 );
2993 $filters = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
2994 $filters = array_filter(preg_split("/(\r\n|\n|\r)/",$filters));
2995 foreach ($filters as $filter) {
2996 if (preg_match('/.+ ACTIVE/i', $filter)) {
2997 $exec_fields = array(
2998 'cmd' => 'sieve',
2999 'task' => 'print',
3000 'script_name' => substr($filter, 0, -7),
3001 'username' => $_data
3002 );
3003 $script = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3004 // Remove first line
3005 return preg_replace('/^.+\n/', '', $script);
3006 }
3007 }
3008 return false;
3009 break;
3010 case 'syncjob_details':
3011 $syncjobdetails = array();
3012 if (!is_numeric($_data)) {
3013 return false;
3014 }
3015 if (isset($_extra) && in_array('no_log', $_extra)) {
3016 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("returned_text", "password1")');
3017 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3018 while($field = array_shift($fields)) {
3019 $shown_fields[] = $field['Field'];
3020 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003021 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003022 `active`
3023 FROM `imapsync` WHERE id = :id");
3024 }
3025 elseif (isset($_extra) && in_array('with_password', $_extra)) {
3026 $stmt = $pdo->prepare("SELECT *,
3027 `active`
3028 FROM `imapsync` WHERE id = :id");
3029 }
3030 else {
3031 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("password1")');
3032 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3033 while($field = array_shift($fields)) {
3034 $shown_fields[] = $field['Field'];
3035 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003036 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003037 `active`
3038 FROM `imapsync` WHERE id = :id");
3039 }
3040 $stmt->execute(array(':id' => $_data));
3041 $syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
3042 if (!empty($syncjobdetails['returned_text'])) {
3043 $syncjobdetails['log'] = $syncjobdetails['returned_text'];
3044 }
3045 else {
3046 $syncjobdetails['log'] = '';
3047 }
3048 unset($syncjobdetails['returned_text']);
3049 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) {
3050 return false;
3051 }
3052 return $syncjobdetails;
3053 break;
3054 case 'syncjobs':
3055 $syncjobdata = array();
3056 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3057 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3058 return false;
3059 }
3060 }
3061 else {
3062 $_data = $_SESSION['mailcow_cc_username'];
3063 }
3064 $stmt = $pdo->prepare("SELECT `id` FROM `imapsync` WHERE `user2` = :username");
3065 $stmt->execute(array(':username' => $_data));
3066 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3067 while($row = array_shift($rows)) {
3068 $syncjobdata[] = $row['id'];
3069 }
3070 return $syncjobdata;
3071 break;
3072 case 'spam_score':
3073 $curl = curl_init();
3074 curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
3075 curl_setopt($curl, CURLOPT_URL,"http://rspamd/actions");
3076 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
3077 $default_actions = curl_exec($curl);
3078 if (!curl_errno($curl)) {
3079 $data_array = json_decode($default_actions, true);
3080 curl_close($curl);
3081 foreach ($data_array as $data) {
3082 if ($data['action'] == 'reject') {
3083 $reject = $data['value'];
3084 continue;
3085 }
3086 elseif ($data['action'] == 'add header') {
3087 $add_header = $data['value'];
3088 continue;
3089 }
3090 }
3091 if (empty($add_header) || empty($reject)) {
3092 // Assume default, set warning
3093 $default = "5, 15";
3094 $_SESSION['return'][] = array(
3095 'type' => 'warning',
3096 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3097 'msg' => 'Could not determine servers default spam score, assuming default'
3098 );
3099 }
3100 else {
3101 $default = $add_header . ', ' . $reject;
3102 }
3103 }
3104 else {
3105 // Assume default, set warning
3106 $default = "5, 15";
3107 $_SESSION['return'][] = array(
3108 'type' => 'warning',
3109 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3110 'msg' => 'Could not determine servers default spam score, assuming default'
3111 );
3112 }
3113 curl_close($curl);
3114 $policydata = array();
3115 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3116 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3117 return false;
3118 }
3119 }
3120 else {
3121 $_data = $_SESSION['mailcow_cc_username'];
3122 }
3123 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
3124 (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
3125 $stmt->execute(array(':username' => $_data));
3126 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
3127 if (empty($num_results)) {
3128 return $default;
3129 }
3130 else {
3131 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'highspamlevel' AND `object` = :username");
3132 $stmt->execute(array(':username' => $_data));
3133 $highspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3134 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'lowspamlevel' AND `object` = :username");
3135 $stmt->execute(array(':username' => $_data));
3136 $lowspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3137 return $lowspamlevel['value'].', '.$highspamlevel['value'];
3138 }
3139 break;
3140 case 'time_limited_aliases':
3141 $tladata = array();
3142 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3143 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3144 return false;
3145 }
3146 }
3147 else {
3148 $_data = $_SESSION['mailcow_cc_username'];
3149 }
3150 $stmt = $pdo->prepare("SELECT `address`,
3151 `goto`,
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003152 `validity`,
3153 `created`,
3154 `modified`
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003155 FROM `spamalias`
3156 WHERE `goto` = :username
3157 AND `validity` >= :unixnow");
3158 $stmt->execute(array(':username' => $_data, ':unixnow' => time()));
3159 $tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
3160 return $tladata;
3161 break;
3162 case 'delimiter_action':
3163 $policydata = array();
3164 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3165 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3166 return false;
3167 }
3168 }
3169 else {
3170 $_data = $_SESSION['mailcow_cc_username'];
3171 }
3172 try {
3173 if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
3174 return "subject";
3175 }
3176 elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
3177 return "subfolder";
3178 }
3179 else {
3180 return "none";
3181 }
3182 }
3183 catch (RedisException $e) {
3184 $_SESSION['return'][] = array(
3185 'type' => 'danger',
3186 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3187 'msg' => array('redis_error', $e)
3188 );
3189 return false;
3190 }
3191 break;
3192 case 'resources':
3193 $resources = array();
3194 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3195 return false;
3196 }
3197 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3198 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` = :domain");
3199 $stmt->execute(array(
3200 ':domain' => $_data,
3201 ));
3202 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3203 while($row = array_shift($rows)) {
3204 $resources[] = $row['username'];
3205 }
3206 }
3207 else {
3208 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
3209 $stmt->execute(array(
3210 ':username' => $_SESSION['mailcow_cc_username'],
3211 ':role' => $_SESSION['mailcow_cc_role'],
3212 ));
3213 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3214 while($row = array_shift($rows)) {
3215 $resources[] = $row['username'];
3216 }
3217 }
3218 return $resources;
3219 break;
3220 case 'alias_domains':
3221 $aliasdomains = array();
3222 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3223 return false;
3224 }
3225 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3226 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain");
3227 $stmt->execute(array(
3228 ':domain' => $_data,
3229 ));
3230 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3231 while($row = array_shift($rows)) {
3232 $aliasdomains[] = $row['alias_domain'];
3233 }
3234 }
3235 else {
3236 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
3237 $stmt->execute(array(
3238 ':username' => $_SESSION['mailcow_cc_username'],
3239 ':role' => $_SESSION['mailcow_cc_role'],
3240 ));
3241 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3242 while($row = array_shift($rows)) {
3243 $aliasdomains[] = $row['alias_domain'];
3244 }
3245 }
3246 return $aliasdomains;
3247 break;
3248 case 'aliases':
3249 $aliases = array();
3250 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3251 return false;
3252 }
3253 $stmt = $pdo->prepare("SELECT `id` FROM `alias` WHERE `address` != `goto` AND `domain` = :domain");
3254 $stmt->execute(array(
3255 ':domain' => $_data,
3256 ));
3257 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3258 while($row = array_shift($rows)) {
3259 $aliases[] = $row['id'];
3260 }
3261 return $aliases;
3262 break;
3263 case 'alias_details':
3264 $aliasdata = array();
3265 $stmt = $pdo->prepare("SELECT
3266 `id`,
3267 `domain`,
3268 `goto`,
3269 `address`,
3270 `public_comment`,
3271 `private_comment`,
3272 `active`,
3273 `sogo_visible`,
3274 `created`,
3275 `modified`
3276 FROM `alias`
3277 WHERE (`id` = :id OR `address` = :address) AND `address` != `goto`");
3278 $stmt->execute(array(
3279 ':id' => $_data,
3280 ':address' => $_data,
3281 ));
3282 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3283 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
3284 $stmt->execute(array(
3285 ':domain' => $row['domain'],
3286 ));
3287 $row_alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
3288 if (isset($row_alias_domain['target_domain']) && !empty($row_alias_domain['target_domain'])) {
3289 $aliasdata['in_primary_domain'] = $row_alias_domain['target_domain'];
3290 }
3291 else {
3292 $aliasdata['in_primary_domain'] = "";
3293 }
3294 $aliasdata['id'] = $row['id'];
3295 $aliasdata['domain'] = $row['domain'];
3296 $aliasdata['public_comment'] = $row['public_comment'];
3297 $aliasdata['private_comment'] = $row['private_comment'];
3298 $aliasdata['domain'] = $row['domain'];
3299 $aliasdata['goto'] = $row['goto'];
3300 $aliasdata['address'] = $row['address'];
3301 (!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
3302 $aliasdata['active'] = $row['active'];
3303 $aliasdata['active_int'] = $row['active'];
3304 $aliasdata['sogo_visible'] = $row['sogo_visible'];
3305 $aliasdata['sogo_visible_int'] = $row['sogo_visible'];
3306 $aliasdata['created'] = $row['created'];
3307 $aliasdata['modified'] = $row['modified'];
3308 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
3309 return false;
3310 }
3311 return $aliasdata;
3312 break;
3313 case 'alias_domain_details':
3314 $aliasdomaindata = array();
3315 $rl = ratelimit('get', 'domain', $_data);
3316 $stmt = $pdo->prepare("SELECT
3317 `alias_domain`,
3318 `target_domain`,
3319 `active`,
3320 `created`,
3321 `modified`
3322 FROM `alias_domain`
3323 WHERE `alias_domain` = :aliasdomain");
3324 $stmt->execute(array(
3325 ':aliasdomain' => $_data,
3326 ));
3327 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3328 $stmt = $pdo->prepare("SELECT `backupmx` FROM `domain` WHERE `domain` = :target_domain");
3329 $stmt->execute(array(
3330 ':target_domain' => $row['target_domain']
3331 ));
3332 $row_parent = $stmt->fetch(PDO::FETCH_ASSOC);
3333 $aliasdomaindata['alias_domain'] = $row['alias_domain'];
3334 $aliasdomaindata['parent_is_backupmx'] = $row_parent['backupmx'];
3335 $aliasdomaindata['target_domain'] = $row['target_domain'];
3336 $aliasdomaindata['active'] = $row['active'];
3337 $aliasdomaindata['active_int'] = $row['active'];
3338 $aliasdomaindata['rl'] = $rl;
3339 $aliasdomaindata['created'] = $row['created'];
3340 $aliasdomaindata['modified'] = $row['modified'];
3341 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdomaindata['target_domain'])) {
3342 return false;
3343 }
3344 return $aliasdomaindata;
3345 break;
3346 case 'domains':
3347 $domains = array();
3348 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
3349 return false;
3350 }
3351 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
3352 WHERE (`domain` IN (
3353 SELECT `domain` from `domain_admins`
3354 WHERE (`active`='1' AND `username` = :username))
3355 )
3356 OR 'admin'= :role");
3357 $stmt->execute(array(
3358 ':username' => $_SESSION['mailcow_cc_username'],
3359 ':role' => $_SESSION['mailcow_cc_role'],
3360 ));
3361 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3362 while($row = array_shift($rows)) {
3363 $domains[] = $row['domain'];
3364 }
3365 return $domains;
3366 break;
3367 case 'domain_details':
3368 $domaindata = array();
3369 $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
3370 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3371 return false;
3372 }
3373 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
3374 $stmt->execute(array(
3375 ':domain' => $_data
3376 ));
3377 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3378 if (!empty($row)) {
3379 $_data = $row['target_domain'];
3380 }
3381 $stmt = $pdo->prepare("SELECT
3382 `domain`,
3383 `description`,
3384 `aliases`,
3385 `mailboxes`,
3386 `defquota`,
3387 `maxquota`,
3388 `quota`,
3389 `relayhost`,
3390 `relay_all_recipients`,
3391 `relay_unknown_only`,
3392 `backupmx`,
3393 `gal`,
3394 `active`
3395 FROM `domain` WHERE `domain`= :domain");
3396 $stmt->execute(array(
3397 ':domain' => $_data
3398 ));
3399 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3400 if (empty($row)) {
3401 return false;
3402 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003403 $stmt = $pdo->prepare("SELECT COUNT(`username`) AS `count`,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003404 COALESCE(SUM(`quota`), 0) AS `in_use`
3405 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003406 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003407 AND `domain` = :domain");
3408 $stmt->execute(array(':domain' => $row['domain']));
3409 $MailboxDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
3410 $stmt = $pdo->prepare("SELECT SUM(bytes) AS `bytes_total`, SUM(messages) AS `msgs_total` FROM `quota2`
3411 WHERE `username` IN (
3412 SELECT `username` FROM `mailbox`
3413 WHERE `domain` = :domain
3414 );");
3415 $stmt->execute(array(':domain' => $row['domain']));
3416 $SumQuotaInUse = $stmt->fetch(PDO::FETCH_ASSOC);
3417 $rl = ratelimit('get', 'domain', $_data);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003418 $domaindata['max_new_mailbox_quota'] = ($row['quota'] * 1048576) - $MailboxDataDomain['in_use'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003419 if ($domaindata['max_new_mailbox_quota'] > ($row['maxquota'] * 1048576)) {
3420 $domaindata['max_new_mailbox_quota'] = ($row['maxquota'] * 1048576);
3421 }
3422 $domaindata['def_new_mailbox_quota'] = $domaindata['max_new_mailbox_quota'];
3423 if ($domaindata['def_new_mailbox_quota'] > ($row['defquota'] * 1048576)) {
3424 $domaindata['def_new_mailbox_quota'] = ($row['defquota'] * 1048576);
3425 }
3426 $domaindata['quota_used_in_domain'] = $MailboxDataDomain['in_use'];
3427 if (!empty($SumQuotaInUse['bytes_total'])) {
3428 $domaindata['bytes_total'] = $SumQuotaInUse['bytes_total'];
3429 }
3430 else {
3431 $domaindata['bytes_total'] = 0;
3432 }
3433 if (!empty($SumQuotaInUse['msgs_total'])) {
3434 $domaindata['msgs_total'] = $SumQuotaInUse['msgs_total'];
3435 }
3436 else {
3437 $domaindata['msgs_total'] = 0;
3438 }
3439 $domaindata['mboxes_in_domain'] = $MailboxDataDomain['count'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003440 $domaindata['mboxes_left'] = $row['mailboxes'] - $MailboxDataDomain['count'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003441 $domaindata['domain_name'] = $row['domain'];
3442 $domaindata['description'] = $row['description'];
3443 $domaindata['max_num_aliases_for_domain'] = $row['aliases'];
3444 $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
3445 $domaindata['def_quota_for_mbox'] = $row['defquota'] * 1048576;
3446 $domaindata['max_quota_for_mbox'] = $row['maxquota'] * 1048576;
3447 $domaindata['max_quota_for_domain'] = $row['quota'] * 1048576;
3448 $domaindata['relayhost'] = $row['relayhost'];
3449 $domaindata['backupmx'] = $row['backupmx'];
3450 $domaindata['backupmx_int'] = $row['backupmx'];
3451 $domaindata['gal'] = $row['gal'];
3452 $domaindata['gal_int'] = $row['gal'];
3453 $domaindata['rl'] = $rl;
3454 $domaindata['active'] = $row['active'];
3455 $domaindata['active_int'] = $row['active'];
3456 $domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
3457 $domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
3458 $domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
3459 $domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003460 $stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003461 WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
3462 AND `address` NOT IN (
3463 SELECT `username` FROM `mailbox`
3464 )");
3465 $stmt->execute(array(
3466 ':domain' => $_data,
3467 ':domain2' => $_data
3468 ));
3469 $AliasDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
3470 (isset($AliasDataDomain['alias_count'])) ? $domaindata['aliases_in_domain'] = $AliasDataDomain['alias_count'] : $domaindata['aliases_in_domain'] = "0";
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003471 $domaindata['aliases_left'] = $row['aliases'] - $AliasDataDomain['alias_count'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003472 if ($_SESSION['mailcow_cc_role'] == "admin")
3473 {
3474 $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS domain_admins FROM `domain_admins` WHERE `domain` = :domain");
3475 $stmt->execute(array(
3476 ':domain' => $_data
3477 ));
3478 $domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
3479 (isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
3480 }
3481 return $domaindata;
3482 break;
3483 case 'mailbox_details':
3484 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3485 return false;
3486 }
3487 $mailboxdata = array();
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003488 if (preg_match('/y|yes/i', getenv('MASTER'))) {
3489 $stmt = $pdo->prepare("SELECT
3490 `domain`.`backupmx`,
3491 `mailbox`.`username`,
3492 `mailbox`.`name`,
3493 `mailbox`.`active`,
3494 `mailbox`.`domain`,
3495 `mailbox`.`local_part`,
3496 `mailbox`.`quota`,
3497 `quota2`.`bytes`,
3498 `attributes`,
3499 `quota2`.`messages`
3500 FROM `mailbox`, `quota2`, `domain`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003501 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
3502 AND `mailbox`.`username` = `quota2`.`username`
3503 AND `domain`.`domain` = `mailbox`.`domain`
3504 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003505 }
3506 else {
3507 $stmt = $pdo->prepare("SELECT
3508 `domain`.`backupmx`,
3509 `mailbox`.`username`,
3510 `mailbox`.`name`,
3511 `mailbox`.`active`,
3512 `mailbox`.`domain`,
3513 `mailbox`.`local_part`,
3514 `mailbox`.`quota`,
3515 `quota2replica`.`bytes`,
3516 `attributes`,
3517 `quota2replica`.`messages`
3518 FROM `mailbox`, `quota2replica`, `domain`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003519 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
3520 AND `mailbox`.`username` = `quota2replica`.`username`
3521 AND `domain`.`domain` = `mailbox`.`domain`
3522 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003523 }
3524 $stmt->execute(array(
3525 ':mailbox' => $_data,
3526 ));
3527 $row = $stmt->fetch(PDO::FETCH_ASSOC);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003528
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003529 $mailboxdata['username'] = $row['username'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003530 $mailboxdata['active'] = $row['active'];
3531 $mailboxdata['active_int'] = $row['active'];
3532 $mailboxdata['domain'] = $row['domain'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003533 $mailboxdata['relayhost'] = $row['relayhost'];
3534 $mailboxdata['name'] = $row['name'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003535 $mailboxdata['local_part'] = $row['local_part'];
3536 $mailboxdata['quota'] = $row['quota'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003537 $mailboxdata['messages'] = $row['messages'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003538 $mailboxdata['attributes'] = json_decode($row['attributes'], true);
3539 $mailboxdata['quota_used'] = intval($row['bytes']);
3540 $mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003541
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003542 if ($mailboxdata['percent_in_use'] === '- ') {
3543 $mailboxdata['percent_class'] = "info";
3544 }
3545 elseif ($mailboxdata['percent_in_use'] >= 90) {
3546 $mailboxdata['percent_class'] = "danger";
3547 }
3548 elseif ($mailboxdata['percent_in_use'] >= 75) {
3549 $mailboxdata['percent_class'] = "warning";
3550 }
3551 else {
3552 $mailboxdata['percent_class'] = "success";
3553 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003554
3555 // Determine last logins
3556 $stmt = $pdo->prepare("SELECT MAX(`datetime`) AS `datetime`, `service` FROM `sasl_log`
3557 WHERE `username` = :mailbox
3558 GROUP BY `service` DESC");
3559 $stmt->execute(array(':mailbox' => $_data));
3560 $SaslLogsData = $stmt->fetchAll(PDO::FETCH_ASSOC);
3561 foreach ($SaslLogsData as $SaslLogs) {
3562 if ($SaslLogs['service'] == 'imap') {
3563 $last_imap_login = strtotime($SaslLogs['datetime']);
3564 }
3565 else if ($SaslLogs['service'] == 'smtp') {
3566 $last_smtp_login = strtotime($SaslLogs['datetime']);
3567 }
3568 else if ($SaslLogs['service'] == 'pop3') {
3569 $last_pop3_login = strtotime($SaslLogs['datetime']);
3570 }
3571 }
3572 if (!isset($last_imap_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
3573 $last_imap_login = 0;
3574 }
3575 if (!isset($last_smtp_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
3576 $last_smtp_login = 0;
3577 }
3578 if (!isset($last_pop3_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
3579 $last_pop3_login = 0;
3580 }
3581 $mailboxdata['last_imap_login'] = $last_imap_login;
3582 $mailboxdata['last_smtp_login'] = $last_smtp_login;
3583 $mailboxdata['last_pop3_login'] = $last_pop3_login;
3584
3585 if (!isset($_extra) || $_extra != 'reduced') {
3586 $rl = ratelimit('get', 'mailbox', $_data);
3587 $stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
3588 $stmt->execute(array(':domain' => $row['domain']));
3589 $DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
3590
3591 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
3592 $stmt->execute(array(':username' => $_data));
3593 $PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
3594 $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
3595 $stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
3596 $MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
3597 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
3598 $stmt->execute(array(':address' => $_data, ':unixnow' => time()));
3599 $SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
3600 $mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
3601 $mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
3602 $mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
3603 if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
3604 $mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
3605 }
3606 if (!empty($rl)) {
3607 $mailboxdata['rl'] = $rl;
3608 $mailboxdata['rl_scope'] = 'mailbox';
3609 }
3610 else {
3611 $mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
3612 $mailboxdata['rl_scope'] = 'domain';
3613 }
3614 $mailboxdata['is_relayed'] = $row['backupmx'];
3615 }
3616
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003617 return $mailboxdata;
3618 break;
3619 case 'resource_details':
3620 $resourcedata = array();
3621 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3622 return false;
3623 }
3624 $stmt = $pdo->prepare("SELECT
3625 `username`,
3626 `name`,
3627 `kind`,
3628 `multiple_bookings`,
3629 `local_part`,
3630 `active`,
3631 `domain`
3632 FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
3633 $stmt->execute(array(
3634 ':resource' => $_data,
3635 ));
3636 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3637 $resourcedata['name'] = $row['username'];
3638 $resourcedata['kind'] = $row['kind'];
3639 $resourcedata['multiple_bookings'] = $row['multiple_bookings'];
3640 $resourcedata['description'] = $row['name'];
3641 $resourcedata['active'] = $row['active'];
3642 $resourcedata['active_int'] = $row['active'];
3643 $resourcedata['domain'] = $row['domain'];
3644 $resourcedata['local_part'] = $row['local_part'];
3645 if (!isset($resourcedata['domain']) ||
3646 (isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
3647 return false;
3648 }
3649 return $resourcedata;
3650 break;
3651 }
3652 break;
3653 case 'delete':
3654 switch ($_type) {
3655 case 'syncjob':
3656 if (!is_array($_data['id'])) {
3657 $ids = array();
3658 $ids[] = $_data['id'];
3659 }
3660 else {
3661 $ids = $_data['id'];
3662 }
3663 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
3664 $_SESSION['return'][] = array(
3665 'type' => 'danger',
3666 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3667 'msg' => 'access_denied'
3668 );
3669 return false;
3670 }
3671 foreach ($ids as $id) {
3672 if (!is_numeric($id)) {
3673 return false;
3674 }
3675 $stmt = $pdo->prepare("SELECT `user2` FROM `imapsync` WHERE id = :id");
3676 $stmt->execute(array(':id' => $id));
3677 $user2 = $stmt->fetch(PDO::FETCH_ASSOC)['user2'];
3678 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) {
3679 $_SESSION['return'][] = array(
3680 'type' => 'danger',
3681 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3682 'msg' => 'access_denied'
3683 );
3684 continue;
3685 }
3686 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `id`= :id");
3687 $stmt->execute(array(':id' => $id));
3688 $_SESSION['return'][] = array(
3689 'type' => 'success',
3690 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3691 'msg' => array('deleted_syncjob', $id)
3692 );
3693 }
3694 break;
3695 case 'filter':
3696 if (!is_array($_data['id'])) {
3697 $ids = array();
3698 $ids[] = $_data['id'];
3699 }
3700 else {
3701 $ids = $_data['id'];
3702 }
3703 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
3704 $_SESSION['return'][] = array(
3705 'type' => 'danger',
3706 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3707 'msg' => 'access_denied'
3708 );
3709 return false;
3710 }
3711 foreach ($ids as $id) {
3712 if (!is_numeric($id)) {
3713 continue;
3714 }
3715 $stmt = $pdo->prepare("SELECT `username` FROM `sieve_filters` WHERE id = :id");
3716 $stmt->execute(array(':id' => $id));
3717 $usr = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
3718 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $usr)) {
3719 $_SESSION['return'][] = array(
3720 'type' => 'danger',
3721 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3722 'msg' => 'access_denied'
3723 );
3724 continue;
3725 }
3726 $stmt = $pdo->prepare("DELETE FROM `sieve_filters` WHERE `id`= :id");
3727 $stmt->execute(array(':id' => $id));
3728 $_SESSION['return'][] = array(
3729 'type' => 'success',
3730 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3731 'msg' => array('delete_filter', $id)
3732 );
3733 }
3734 break;
3735 case 'time_limited_alias':
3736 if (!is_array($_data['address'])) {
3737 $addresses = array();
3738 $addresses[] = $_data['address'];
3739 }
3740 else {
3741 $addresses = $_data['address'];
3742 }
3743 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
3744 $_SESSION['return'][] = array(
3745 'type' => 'danger',
3746 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3747 'msg' => 'access_denied'
3748 );
3749 return false;
3750 }
3751 foreach ($addresses as $address) {
3752 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
3753 $stmt->execute(array(':address' => $address));
3754 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
3755 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
3756 $_SESSION['return'][] = array(
3757 'type' => 'danger',
3758 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3759 'msg' => 'access_denied'
3760 );
3761 continue;
3762 }
3763 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username AND `address` = :item");
3764 $stmt->execute(array(
3765 ':username' => $goto,
3766 ':item' => $address
3767 ));
3768 $_SESSION['return'][] = array(
3769 'type' => 'success',
3770 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3771 'msg' => array('mailbox_modified', htmlspecialchars($goto))
3772 );
3773 }
3774 break;
3775 case 'eas_cache':
3776 if (!is_array($_data['username'])) {
3777 $usernames = array();
3778 $usernames[] = $_data['username'];
3779 }
3780 else {
3781 $usernames = $_data['username'];
3782 }
3783 if (!isset($_SESSION['acl']['eas_reset']) || $_SESSION['acl']['eas_reset'] != "1" ) {
3784 $_SESSION['return'][] = array(
3785 'type' => 'danger',
3786 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3787 'msg' => 'access_denied'
3788 );
3789 return false;
3790 }
3791 foreach ($usernames as $username) {
3792 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
3793 $_SESSION['return'][] = array(
3794 'type' => 'danger',
3795 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3796 'msg' => 'access_denied'
3797 );
3798 continue;
3799 }
3800 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
3801 $stmt->execute(array(
3802 ':username' => $username
3803 ));
3804 $_SESSION['return'][] = array(
3805 'type' => 'success',
3806 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3807 'msg' => array('eas_reset', htmlspecialchars($username))
3808 );
3809 }
3810 break;
3811 case 'sogo_profile':
3812 if (!is_array($_data['username'])) {
3813 $usernames = array();
3814 $usernames[] = $_data['username'];
3815 }
3816 else {
3817 $usernames = $_data['username'];
3818 }
3819 if (!isset($_SESSION['acl']['sogo_profile_reset']) || $_SESSION['acl']['sogo_profile_reset'] != "1" ) {
3820 $_SESSION['return'][] = array(
3821 'type' => 'danger',
3822 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3823 'msg' => 'access_denied'
3824 );
3825 return false;
3826 }
3827 foreach ($usernames as $username) {
3828 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
3829 $_SESSION['return'][] = array(
3830 'type' => 'danger',
3831 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3832 'msg' => 'access_denied'
3833 );
3834 continue;
3835 }
3836 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
3837 $stmt->execute(array(
3838 ':username' => $username
3839 ));
3840 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
3841 $stmt->execute(array(
3842 ':username' => $username
3843 ));
3844 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
3845 $stmt->execute(array(
3846 ':username' => $username
3847 ));
3848 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
3849 $stmt->execute(array(
3850 ':username' => $username
3851 ));
3852 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
3853 $stmt->execute(array(
3854 ':username' => $username
3855 ));
3856 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
3857 $stmt->execute(array(
3858 ':username' => $username
3859 ));
3860 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
3861 $stmt->execute(array(
3862 ':username' => $username
3863 ));
3864 $_SESSION['return'][] = array(
3865 'type' => 'success',
3866 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3867 'msg' => array('sogo_profile_reset', htmlspecialchars($username))
3868 );
3869 }
3870 break;
3871 case 'domain':
3872 if (!is_array($_data['domain'])) {
3873 $domains = array();
3874 $domains[] = $_data['domain'];
3875 }
3876 else {
3877 $domains = $_data['domain'];
3878 }
3879 if ($_SESSION['mailcow_cc_role'] != "admin") {
3880 $_SESSION['return'][] = array(
3881 'type' => 'danger',
3882 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3883 'msg' => 'access_denied'
3884 );
3885 return false;
3886 }
3887 foreach ($domains as $domain) {
3888 if (!is_valid_domain_name($domain)) {
3889 $_SESSION['return'][] = array(
3890 'type' => 'danger',
3891 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3892 'msg' => 'domain_invalid'
3893 );
3894 continue;
3895 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003896 $domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003897 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
3898 WHERE `domain` = :domain");
3899 $stmt->execute(array(':domain' => $domain));
3900 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
3901 if ($num_results != 0 || !empty($num_results)) {
3902 $_SESSION['return'][] = array(
3903 'type' => 'danger',
3904 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3905 'msg' => array('domain_not_empty', $domain)
3906 );
3907 continue;
3908 }
3909 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $domain);
3910 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
3911 if ($maildir_gc['type'] != 'success') {
3912 $_SESSION['return'][] = array(
3913 'type' => 'warning',
3914 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3915 'msg' => 'Could not move mail storage to garbage collector: ' . $maildir_gc['msg']
3916 );
3917 }
3918 $stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
3919 $stmt->execute(array(
3920 ':domain' => $domain,
3921 ));
3922 $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `domain` = :domain");
3923 $stmt->execute(array(
3924 ':domain' => $domain,
3925 ));
3926 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :domain");
3927 $stmt->execute(array(
3928 ':domain' => $domain,
3929 ));
3930 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `target_domain` = :domain");
3931 $stmt->execute(array(
3932 ':domain' => $domain,
3933 ));
3934 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `domain` = :domain");
3935 $stmt->execute(array(
3936 ':domain' => $domain,
3937 ));
3938 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` LIKE :domain");
3939 $stmt->execute(array(
3940 ':domain' => '%@'.$domain,
3941 ));
3942 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain");
3943 $stmt->execute(array(
3944 ':domain' => '%@'.$domain,
3945 ));
3946 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` LIKE :domain");
3947 $stmt->execute(array(
3948 ':domain' => '%@'.$domain,
3949 ));
3950 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` LIKE :domain");
3951 $stmt->execute(array(
3952 ':domain' => '%@'.$domain,
3953 ));
3954 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
3955 $stmt->execute(array(
3956 ':domain' => '%@'.$domain,
3957 ));
3958 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
3959 $stmt->execute(array(
3960 ':domain' => $domain,
3961 ));
3962 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
3963 $stmt->execute(array(
3964 ':domain' => $domain,
3965 ));
3966 $stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
3967 $stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
3968 try {
3969 $redis->hDel('DOMAIN_MAP', $domain);
3970 $redis->hDel('RL_VALUE', $domain);
3971 }
3972 catch (RedisException $e) {
3973 $_SESSION['return'][] = array(
3974 'type' => 'danger',
3975 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3976 'msg' => array('redis_error', $e)
3977 );
3978 continue;
3979 }
3980 $_SESSION['return'][] = array(
3981 'type' => 'success',
3982 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3983 'msg' => array('domain_removed', htmlspecialchars($domain))
3984 );
3985 }
3986 break;
3987 case 'alias':
3988 if (!is_array($_data['id'])) {
3989 $ids = array();
3990 $ids[] = $_data['id'];
3991 }
3992 else {
3993 $ids = $_data['id'];
3994 }
3995 foreach ($ids as $id) {
3996 $alias_data = mailbox('get', 'alias_details', $id);
3997 if (empty($alias_data)) {
3998 $_SESSION['return'][] = array(
3999 'type' => 'danger',
4000 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4001 'msg' => 'access_denied'
4002 );
4003 continue;
4004 }
4005 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `id` = :id");
4006 $stmt->execute(array(
4007 ':id' => $alias_data['id']
4008 ));
4009 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `send_as` = :alias_address");
4010 $stmt->execute(array(
4011 ':alias_address' => $alias_data['address']
4012 ));
4013 $_SESSION['return'][] = array(
4014 'type' => 'success',
4015 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4016 'msg' => array('alias_removed', htmlspecialchars($alias_data['address']))
4017 );
4018 }
4019 break;
4020 case 'alias_domain':
4021 if (!is_array($_data['alias_domain'])) {
4022 $alias_domains = array();
4023 $alias_domains[] = $_data['alias_domain'];
4024 }
4025 else {
4026 $alias_domains = $_data['alias_domain'];
4027 }
4028 foreach ($alias_domains as $alias_domain) {
4029 if (!is_valid_domain_name($alias_domain)) {
4030 $_SESSION['return'][] = array(
4031 'type' => 'danger',
4032 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4033 'msg' => 'domain_invalid'
4034 );
4035 continue;
4036 }
4037 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
4038 WHERE `alias_domain`= :alias_domain");
4039 $stmt->execute(array(':alias_domain' => $alias_domain));
4040 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
4041 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
4042 $_SESSION['return'][] = array(
4043 'type' => 'danger',
4044 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4045 'msg' => 'access_denied'
4046 );
4047 continue;
4048 }
4049 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
4050 $stmt->execute(array(
4051 ':alias_domain' => $alias_domain,
4052 ));
4053 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :alias_domain");
4054 $stmt->execute(array(
4055 ':alias_domain' => $alias_domain,
4056 ));
4057 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
4058 $stmt->execute(array(
4059 ':alias_domain' => $alias_domain,
4060 ));
4061 try {
4062 $redis->hDel('DOMAIN_MAP', $alias_domain);
4063 $redis->hDel('RL_VALUE', $domain);
4064 }
4065 catch (RedisException $e) {
4066 $_SESSION['return'][] = array(
4067 'type' => 'danger',
4068 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4069 'msg' => array('redis_error', $e)
4070 );
4071 continue;
4072 }
4073 $_SESSION['return'][] = array(
4074 'type' => 'success',
4075 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4076 'msg' => array('alias_domain_removed', htmlspecialchars($alias_domain))
4077 );
4078 }
4079 break;
4080 case 'mailbox':
4081 if (!is_array($_data['username'])) {
4082 $usernames = array();
4083 $usernames[] = $_data['username'];
4084 }
4085 else {
4086 $usernames = $_data['username'];
4087 }
4088 foreach ($usernames as $username) {
4089 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
4090 $_SESSION['return'][] = array(
4091 'type' => 'danger',
4092 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4093 'msg' => 'access_denied'
4094 );
4095 continue;
4096 }
4097 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
4098 $_SESSION['return'][] = array(
4099 'type' => 'danger',
4100 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4101 'msg' => 'access_denied'
4102 );
4103 continue;
4104 }
4105 $mailbox_details = mailbox('get', 'mailbox_details', $username);
4106 if (!empty($mailbox_details['domain']) && !empty($mailbox_details['local_part'])) {
4107 $maildir = $mailbox_details['domain'] . '/' . $mailbox_details['local_part'];
4108 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $maildir);
4109 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
4110 if ($maildir_gc['type'] != 'success') {
4111 $_SESSION['return'][] = array(
4112 'type' => 'warning',
4113 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4114 'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
4115 );
4116 }
4117 }
4118 else {
4119 $_SESSION['return'][] = array(
4120 'type' => 'warning',
4121 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4122 'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty'
4123 );
4124 }
4125 if (strtolower(getenv('SKIP_SOLR')) == 'n') {
4126 $curl = curl_init();
4127 curl_setopt($curl, CURLOPT_URL, 'http://solr:8983/solr/dovecot-fts/update?commit=true');
4128 curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: text/xml'));
4129 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
4130 curl_setopt($curl, CURLOPT_POST, 1);
4131 curl_setopt($curl, CURLOPT_POSTFIELDS, '<delete><query>user:' . $username . '</query></delete>');
4132 curl_setopt($curl, CURLOPT_TIMEOUT, 30);
4133 $response = curl_exec($curl);
4134 if ($response === false) {
4135 $err = curl_error($curl);
4136 $_SESSION['return'][] = array(
4137 'type' => 'warning',
4138 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4139 'msg' => 'Could not remove Solr index: ' . print_r($err, true)
4140 );
4141 }
4142 curl_close($curl);
4143 }
4144 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
4145 $stmt->execute(array(
4146 ':username' => $username
4147 ));
4148 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username");
4149 $stmt->execute(array(
4150 ':username' => $username
4151 ));
4152 $stmt = $pdo->prepare("DELETE FROM `quarantine` WHERE `rcpt` = :username");
4153 $stmt->execute(array(
4154 ':username' => $username
4155 ));
4156 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :username");
4157 $stmt->execute(array(
4158 ':username' => $username
4159 ));
4160 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` = :username");
4161 $stmt->execute(array(
4162 ':username' => $username
4163 ));
4164 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
4165 $stmt->execute(array(
4166 ':username' => $username
4167 ));
4168 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :username");
4169 $stmt->execute(array(
4170 ':username' => $username
4171 ));
4172 // fk, better safe than sorry
4173 $stmt = $pdo->prepare("DELETE FROM `user_acl` WHERE `username` = :username");
4174 $stmt->execute(array(
4175 ':username' => $username
4176 ));
4177 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username");
4178 $stmt->execute(array(
4179 ':username' => $username
4180 ));
4181 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `user2` = :username");
4182 $stmt->execute(array(
4183 ':username' => $username
4184 ));
4185 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username");
4186 $stmt->execute(array(
4187 ':username' => $username
4188 ));
4189 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
4190 $stmt->execute(array(
4191 ':username' => $username
4192 ));
4193 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4194 $stmt->execute(array(
4195 ':username' => $username
4196 ));
4197 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
4198 $stmt->execute(array(
4199 ':username' => $username
4200 ));
4201 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4202 $stmt->execute(array(
4203 ':username' => $username
4204 ));
4205 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4206 $stmt->execute(array(
4207 ':username' => $username
4208 ));
4209 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4210 $stmt->execute(array(
4211 ':username' => $username
4212 ));
4213 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
4214 $stmt->execute(array(
4215 ':username' => $username
4216 ));
4217 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :username");
4218 $stmt->execute(array(
4219 ':username' => $username
4220 ));
4221 $stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` WHERE `user_id` = :username");
4222 $stmt->execute(array(
4223 ':username' => $username
4224 ));
4225 $stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `user_id` = :username");
4226 $stmt->execute(array(
4227 ':username' => $username
4228 ));
4229 $stmt = $pdo->prepare("DELETE FROM `oauth_authorization_codes` WHERE `user_id` = :username");
4230 $stmt->execute(array(
4231 ':username' => $username
4232 ));
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004233 $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
4234 $stmt->execute(array(
4235 ':username' => $username,
4236 ));
4237 $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
4238 $stmt->execute(array(
4239 ':username' => $username,
4240 ));
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004241 $stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
4242 WHERE `goto` REGEXP :username");
4243 $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
4244 $GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
4245 foreach ($GotoData as $gotos) {
4246 $goto_exploded = explode(',', $gotos['goto']);
4247 if (($key = array_search($username, $goto_exploded)) !== false) {
4248 unset($goto_exploded[$key]);
4249 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004250 $gotos_rebuild = implode(',', (array)$goto_exploded);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004251 $stmt = $pdo->prepare("UPDATE `alias` SET
4252 `goto` = :goto
4253 WHERE `address` = :address");
4254 $stmt->execute(array(
4255 ':goto' => $gotos_rebuild,
4256 ':address' => $gotos['address']
4257 ));
4258 }
4259 try {
4260 $redis->hDel('RL_VALUE', $username);
4261 }
4262 catch (RedisException $e) {
4263 $_SESSION['return'][] = array(
4264 'type' => 'danger',
4265 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4266 'msg' => array('redis_error', $e)
4267 );
4268 continue;
4269 }
4270 $_SESSION['return'][] = array(
4271 'type' => 'success',
4272 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4273 'msg' => array('mailbox_removed', htmlspecialchars($username))
4274 );
4275 }
4276 break;
4277 case 'resource':
4278 if (!is_array($_data['name'])) {
4279 $names = array();
4280 $names[] = $_data['name'];
4281 }
4282 else {
4283 $names = $_data['name'];
4284 }
4285 foreach ($names as $name) {
4286 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
4287 $_SESSION['return'][] = array(
4288 'type' => 'danger',
4289 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4290 'msg' => 'access_denied'
4291 );
4292 continue;
4293 }
4294 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
4295 $_SESSION['return'][] = array(
4296 'type' => 'danger',
4297 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4298 'msg' => 'access_denied'
4299 );
4300 continue;
4301 }
4302 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
4303 $stmt->execute(array(
4304 ':username' => $name
4305 ));
4306 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
4307 $stmt->execute(array(
4308 ':username' => $name
4309 ));
4310 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4311 $stmt->execute(array(
4312 ':username' => $name
4313 ));
4314 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
4315 $stmt->execute(array(
4316 ':username' => $name
4317 ));
4318 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4319 $stmt->execute(array(
4320 ':username' => $name
4321 ));
4322 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4323 $stmt->execute(array(
4324 ':username' => $name
4325 ));
4326 $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4327 $stmt->execute(array(
4328 ':username' => $name
4329 ));
4330 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
4331 $stmt->execute(array(
4332 ':username' => $name
4333 ));
4334 $_SESSION['return'][] = array(
4335 'type' => 'success',
4336 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4337 'msg' => array('resource_removed', htmlspecialchars($name))
4338 );
4339 }
4340 break;
4341 }
4342 break;
4343 }
4344 if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox', 'resource'))) {
4345 update_sogo_static_view();
4346 }
4347}