blob: 68cb50f1b2cdfbb279c220deeea3b9c75b9801cb [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']);
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100339
340 // validate custom params
341 foreach (explode('-', $custom_params) as $param){
342 if(empty($param)) continue;
343
344 // extract option
345 if (str_contains($param, '=')) $param = explode('=', $param)[0];
346 else $param = rtrim($param, ' ');
347 // remove first char if first char is -
348 if ($param[0] == '-') $param = ltrim($param, $param[0]);
349
350 if (str_contains($param, ' ')) {
351 // bad char
352 $_SESSION['return'][] = array(
353 'type' => 'danger',
354 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
355 'msg' => 'bad character SPACE'
356 );
357 return false;
358 }
359
360 // check if param is whitelisted
361 if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
362 // bad option
363 $_SESSION['return'][] = array(
364 'type' => 'danger',
365 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
366 'msg' => 'bad option '. $param
367 );
368 return false;
369 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100370 }
371 if (empty($subfolder2)) {
372 $subfolder2 = "";
373 }
374 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
375 $maxage = "0";
376 }
377 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
378 $timeout1 = "600";
379 }
380 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
381 $timeout2 = "600";
382 }
383 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
384 $maxbytespersecond = "0";
385 }
386 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
387 $_SESSION['return'][] = array(
388 'type' => 'danger',
389 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
390 'msg' => 'access_denied'
391 );
392 return false;
393 }
394 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
395 $_SESSION['return'][] = array(
396 'type' => 'danger',
397 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
398 'msg' => 'access_denied'
399 );
400 return false;
401 }
402 // if (!is_valid_domain_name($host1)) {
403 // $_SESSION['return'][] = array(
404 // 'type' => 'danger',
405 // 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
406 // 'msg' => 'access_denied'
407 // );
408 // return false;
409 // }
410 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
411 $_SESSION['return'][] = array(
412 'type' => 'danger',
413 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
414 'msg' => 'access_denied'
415 );
416 return false;
417 }
418 if (@preg_match("/" . $exclude . "/", null) === false) {
419 $_SESSION['return'][] = array(
420 'type' => 'danger',
421 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
422 'msg' => 'access_denied'
423 );
424 return false;
425 }
426 $stmt = $pdo->prepare("SELECT '1' FROM `imapsync`
427 WHERE `user2` = :user2 AND `user1` = :user1 AND `host1` = :host1");
428 $stmt->execute(array(':user1' => $user1, ':user2' => $username, ':host1' => $host1));
429 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
430 if ($num_results != 0) {
431 $_SESSION['return'][] = array(
432 'type' => 'danger',
433 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
434 'msg' => array('object_exists', htmlspecialchars($host1 . ' / ' . $user1))
435 );
436 return false;
437 }
438 $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`)
439 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)");
440 $stmt->execute(array(
441 ':user2' => $username,
442 ':custom_params' => $custom_params,
443 ':exclude' => $exclude,
444 ':maxage' => $maxage,
445 ':delete1' => $delete1,
446 ':delete2' => $delete2,
447 ':timeout1' => $timeout1,
448 ':timeout2' => $timeout2,
449 ':automap' => $automap,
450 ':skipcrossduplicates' => $skipcrossduplicates,
451 ':maxbytespersecond' => $maxbytespersecond,
452 ':subscribeall' => $subscribeall,
453 ':subfolder2' => $subfolder2,
454 ':host1' => $host1,
455 ':authmech1' => 'PLAIN',
456 ':user1' => $user1,
457 ':password1' => $password1,
458 ':mins_interval' => $mins_interval,
459 ':port1' => $port1,
460 ':enc1' => $enc1,
461 ':delete2duplicates' => $delete2duplicates,
462 ':active' => $active,
463 ));
464 $_SESSION['return'][] = array(
465 'type' => 'success',
466 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
467 'msg' => array('mailbox_modified', $username)
468 );
469 break;
470 case 'domain':
471 if ($_SESSION['mailcow_cc_role'] != "admin") {
472 $_SESSION['return'][] = array(
473 'type' => 'danger',
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100474 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100475 'msg' => 'access_denied'
476 );
477 return false;
478 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200479 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100480 $description = $_data['description'];
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100481 if (empty($description)) $description = $domain;
482 $tags = (array)$_data['tags'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200483 $aliases = (int)$_data['aliases'];
484 $mailboxes = (int)$_data['mailboxes'];
485 $defquota = (int)$_data['defquota'];
486 $maxquota = (int)$_data['maxquota'];
487 $restart_sogo = (int)$_data['restart_sogo'];
488 $quota = (int)$_data['quota'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100489 if ($defquota > $maxquota) {
490 $_SESSION['return'][] = array(
491 'type' => 'danger',
492 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
493 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
494 );
495 return false;
496 }
497 if ($maxquota > $quota) {
498 $_SESSION['return'][] = array(
499 'type' => 'danger',
500 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
501 'msg' => 'mailbox_quota_exceeds_domain_quota'
502 );
503 return false;
504 }
505 if ($defquota == "0" || empty($defquota)) {
506 $_SESSION['return'][] = array(
507 'type' => 'danger',
508 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
509 'msg' => 'defquota_empty'
510 );
511 return false;
512 }
513 if ($maxquota == "0" || empty($maxquota)) {
514 $_SESSION['return'][] = array(
515 'type' => 'danger',
516 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
517 'msg' => 'maxquota_empty'
518 );
519 return false;
520 }
521 $active = intval($_data['active']);
522 $relay_all_recipients = intval($_data['relay_all_recipients']);
523 $relay_unknown_only = intval($_data['relay_unknown_only']);
524 $backupmx = intval($_data['backupmx']);
525 $gal = intval($_data['gal']);
526 if ($relay_all_recipients == 1) {
527 $backupmx = '1';
528 }
529 if ($relay_unknown_only == 1) {
530 $backupmx = 1;
531 $relay_all_recipients = 1;
532 }
533 if (!is_valid_domain_name($domain)) {
534 $_SESSION['return'][] = array(
535 'type' => 'danger',
536 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
537 'msg' => 'domain_invalid'
538 );
539 return false;
540 }
541 foreach (array($quota, $maxquota, $mailboxes, $aliases) as $data) {
542 if (!is_numeric($data)) {
543 $_SESSION['return'][] = array(
544 'type' => 'danger',
545 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
546 'msg' => array('object_is_not_numeric', htmlspecialchars($data))
547 );
548 return false;
549 }
550 }
551 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
552 WHERE `domain` = :domain");
553 $stmt->execute(array(':domain' => $domain));
554 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
555 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
556 WHERE `alias_domain` = :domain");
557 $stmt->execute(array(':domain' => $domain));
558 $num_results = $num_results + count($stmt->fetchAll(PDO::FETCH_ASSOC));
559 if ($num_results != 0) {
560 $_SESSION['return'][] = array(
561 'type' => 'danger',
562 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
563 'msg' => array('domain_exists', htmlspecialchars($domain))
564 );
565 return false;
566 }
567 if ($domain == getenv('MAILCOW_HOSTNAME')) {
568 $_SESSION['return'][] = array(
569 'type' => 'danger',
570 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
571 'msg' => 'domain_cannot_match_hostname'
572 );
573 return false;
574 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100575
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100576 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
577 $stmt->execute(array(
578 ':domain' => '%@' . $domain
579 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100580 // save domain
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100581 $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
582 VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
583 $stmt->execute(array(
584 ':domain' => $domain,
585 ':description' => $description,
586 ':aliases' => $aliases,
587 ':mailboxes' => $mailboxes,
588 ':defquota' => $defquota,
589 ':maxquota' => $maxquota,
590 ':quota' => $quota,
591 ':backupmx' => $backupmx,
592 ':gal' => $gal,
593 ':active' => $active,
594 ':relay_unknown_only' => $relay_unknown_only,
595 ':relay_all_recipients' => $relay_all_recipients
596 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100597 // save tags
598 foreach($tags as $index => $tag){
599 if (empty($tag)) continue;
600 if ($index > $GLOBALS['TAGGING_LIMIT']) {
601 $_SESSION['return'][] = array(
602 'type' => 'warning',
603 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
604 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
605 );
606 break;
607 }
608 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
609 $stmt->execute(array(
610 ':domain' => $domain,
611 ':tag_name' => $tag,
612 ));
613 }
614
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100615 try {
616 $redis->hSet('DOMAIN_MAP', $domain, 1);
617 }
618 catch (RedisException $e) {
619 $_SESSION['return'][] = array(
620 'type' => 'danger',
621 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
622 'msg' => array('redis_error', $e)
623 );
624 return false;
625 }
626 if (!empty(intval($_data['rl_value']))) {
627 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
628 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100629 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100630 if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
631 $_SESSION['return'][] = array(
632 'type' => 'success',
633 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
634 'msg' => 'domain_add_dkim_available'
635 );
636 }
637 else {
638 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
639 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100640 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100641 if (!empty($restart_sogo)) {
642 $restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
643 if ($restart_response['type'] == "success") {
644 $_SESSION['return'][] = array(
645 'type' => 'success',
646 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
647 'msg' => array('domain_added', htmlspecialchars($domain))
648 );
649 return true;
650 }
651 else {
652 $_SESSION['return'][] = array(
653 'type' => 'warning',
654 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
655 'msg' => 'domain_added_sogo_failed'
656 );
657 return false;
658 }
659 }
660 $_SESSION['return'][] = array(
661 'type' => 'success',
662 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
663 'msg' => array('domain_added', htmlspecialchars($domain))
664 );
665 return true;
666 break;
667 case 'alias':
668 $addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
669 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
670 $active = intval($_data['active']);
671 $sogo_visible = intval($_data['sogo_visible']);
672 $goto_null = intval($_data['goto_null']);
673 $goto_spam = intval($_data['goto_spam']);
674 $goto_ham = intval($_data['goto_ham']);
675 $private_comment = $_data['private_comment'];
676 $public_comment = $_data['public_comment'];
677 if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
678 $_SESSION['return'][] = array(
679 'type' => 'danger',
680 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
681 'msg' => 'comment_too_long'
682 );
683 return false;
684 }
685 if (empty($addresses[0])) {
686 $_SESSION['return'][] = array(
687 'type' => 'danger',
688 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
689 'msg' => 'alias_empty'
690 );
691 return false;
692 }
693 if (empty($gotos[0]) && ($goto_null + $goto_spam + $goto_ham == 0)) {
694 $_SESSION['return'][] = array(
695 'type' => 'danger',
696 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
697 'msg' => 'goto_empty'
698 );
699 return false;
700 }
701 if ($goto_null == "1") {
702 $goto = "null@localhost";
703 }
704 elseif ($goto_spam == "1") {
705 $goto = "spam@localhost";
706 }
707 elseif ($goto_ham == "1") {
708 $goto = "ham@localhost";
709 }
710 else {
711 foreach ($gotos as $i => &$goto) {
712 if (empty($goto)) {
713 continue;
714 }
715 $goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
716 $goto_local_part = strstr($goto, '@', true);
717 $goto = $goto_local_part.'@'.$goto_domain;
718 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
719 WHERE `kind` REGEXP 'location|thing|group'
720 AND `username`= :goto");
721 $stmt->execute(array(':goto' => $goto));
722 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
723 if ($num_results != 0) {
724 $_SESSION['return'][] = array(
725 'type' => 'danger',
726 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
727 'msg' => array('goto_invalid', htmlspecialchars($goto))
728 );
729 unset($gotos[$i]);
730 continue;
731 }
732 if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
733 $_SESSION['return'][] = array(
734 'type' => 'danger',
735 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
736 'msg' => array('goto_invalid', htmlspecialchars($goto))
737 );
738 unset($gotos[$i]);
739 continue;
740 }
741 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200742 $gotos = array_unique($gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100743 $gotos = array_filter($gotos);
744 if (empty($gotos)) { return false; }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200745 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100746 }
747 foreach ($addresses as $address) {
748 if (empty($address)) {
749 continue;
750 }
751 if (in_array($address, $gotos)) {
752 continue;
753 }
754 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
755 $local_part = strstr($address, '@', true);
756 $address = $local_part.'@'.$domain;
757 $domaindata = mailbox('get', 'domain_details', $domain);
758 if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
759 $_SESSION['return'][] = array(
760 'type' => 'danger',
761 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
762 'msg' => 'max_alias_exceeded'
763 );
764 return false;
765 }
766 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
767 WHERE `address`= :address OR `address` IN (
768 SELECT `username` FROM `mailbox`, `alias_domain`
769 WHERE (
770 `alias_domain`.`alias_domain` = :address_d
771 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
772 $stmt->execute(array(
773 ':address' => $address,
774 ':address_l' => $local_part,
775 ':address_d' => $domain
776 ));
777 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
778 if ($num_results != 0) {
779 $_SESSION['return'][] = array(
780 'type' => 'danger',
781 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
782 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
783 );
784 continue;
785 }
786 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
787 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
788 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
789 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
790 if ($num_results == 0) {
791 $_SESSION['return'][] = array(
792 'type' => 'danger',
793 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
794 'msg' => array('domain_not_found', htmlspecialchars($domain))
795 );
796 continue;
797 }
798 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
799 WHERE `address`= :address");
800 $stmt->execute(array(':address' => $address));
801 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
802 if ($num_results != 0) {
803 $_SESSION['return'][] = array(
804 'type' => 'danger',
805 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
806 'msg' => array('is_spam_alias', htmlspecialchars($address))
807 );
808 continue;
809 }
810 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
811 $_SESSION['return'][] = array(
812 'type' => 'danger',
813 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
814 'msg' => array('alias_invalid', $address)
815 );
816 continue;
817 }
818 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
819 $_SESSION['return'][] = array(
820 'type' => 'danger',
821 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
822 'msg' => 'access_denied'
823 );
824 continue;
825 }
826 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `active`)
827 VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :active)");
828 if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
829 $stmt->execute(array(
830 ':address' => '@'.$domain,
831 ':public_comment' => $public_comment,
832 ':private_comment' => $private_comment,
833 ':address' => '@'.$domain,
834 ':goto' => $goto,
835 ':domain' => $domain,
836 ':sogo_visible' => $sogo_visible,
837 ':active' => $active
838 ));
839 }
840 else {
841 $stmt->execute(array(
842 ':address' => $address,
843 ':public_comment' => $public_comment,
844 ':private_comment' => $private_comment,
845 ':goto' => $goto,
846 ':domain' => $domain,
847 ':sogo_visible' => $sogo_visible,
848 ':active' => $active
849 ));
850 }
851 $id = $pdo->lastInsertId();
852 $_SESSION['return'][] = array(
853 'type' => 'success',
854 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
855 'msg' => array('alias_added', $address, $id)
856 );
857 }
858 break;
859 case 'alias_domain':
860 $active = intval($_data['active']);
861 $alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain']));
862 $alias_domains = array_filter($alias_domains);
863 $target_domain = idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46);
864 if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) {
865 $_SESSION['return'][] = array(
866 'type' => 'danger',
867 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
868 'msg' => 'access_denied'
869 );
870 return false;
871 }
872 if (!is_valid_domain_name($target_domain)) {
873 $_SESSION['return'][] = array(
874 'type' => 'danger',
875 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
876 'msg' => 'target_domain_invalid'
877 );
878 return false;
879 }
880 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
881 $_SESSION['return'][] = array(
882 'type' => 'danger',
883 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
884 'msg' => 'access_denied'
885 );
886 return false;
887 }
888 foreach ($alias_domains as $i => $alias_domain) {
889 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
890 if (!is_valid_domain_name($alias_domain)) {
891 $_SESSION['return'][] = array(
892 'type' => 'danger',
893 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
894 'msg' => array('alias_domain_invalid', htmlspecialchars(alias_domain))
895 );
896 continue;
897 }
898 if ($alias_domain == $target_domain) {
899 $_SESSION['return'][] = array(
900 'type' => 'danger',
901 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
902 'msg' => array('aliasd_targetd_identical', htmlspecialchars($target_domain))
903 );
904 continue;
905 }
906 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
907 WHERE `domain`= :target_domain");
908 $stmt->execute(array(':target_domain' => $target_domain));
909 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
910 if ($num_results == 0) {
911 $_SESSION['return'][] = array(
912 'type' => 'danger',
913 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
914 'msg' => array('targetd_not_found', htmlspecialchars($target_domain))
915 );
916 continue;
917 }
918 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
919 WHERE `domain`= :target_domain AND `backupmx` = '1'");
920 $stmt->execute(array(':target_domain' => $target_domain));
921 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
922 if ($num_results == 1) {
923 $_SESSION['return'][] = array(
924 'type' => 'danger',
925 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
926 'msg' => array('targetd_relay_domain', htmlspecialchars($target_domain))
927 );
928 continue;
929 }
930 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain
931 UNION
932 SELECT `domain` FROM `domain` WHERE `domain`= :alias_domain_in_domain");
933 $stmt->execute(array(':alias_domain' => $alias_domain, ':alias_domain_in_domain' => $alias_domain));
934 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
935 if ($num_results != 0) {
936 $_SESSION['return'][] = array(
937 'type' => 'danger',
938 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
939 'msg' => array('alias_domain_invalid', $alias_domain)
940 );
941 continue;
942 }
943 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
944 $stmt->execute(array(
945 ':domain' => '%@' . $domain
946 ));
947 $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
948 VALUES (:alias_domain, :target_domain, :active)");
949 $stmt->execute(array(
950 ':alias_domain' => $alias_domain,
951 ':target_domain' => $target_domain,
952 ':active' => $active
953 ));
954 try {
955 $redis->hSet('DOMAIN_MAP', $alias_domain, 1);
956 }
957 catch (RedisException $e) {
958 $_SESSION['return'][] = array(
959 'type' => 'danger',
960 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
961 'msg' => array('redis_error', $e)
962 );
963 return false;
964 }
965 if (!empty(intval($_data['rl_value']))) {
966 ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
967 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100968 if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100969 if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
970 $_SESSION['return'][] = array(
971 'type' => 'success',
972 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
973 'msg' => 'domain_add_dkim_available'
974 );
975 }
976 else {
977 dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
978 }
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100979 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100980 $_SESSION['return'][] = array(
981 'type' => 'success',
982 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
983 'msg' => array('aliasd_added', htmlspecialchars($alias_domain))
984 );
985 }
986 break;
987 case 'mailbox':
988 $local_part = strtolower(trim($_data['local_part']));
989 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
990 $username = $local_part . '@' . $domain;
991 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
992 $_SESSION['return'][] = array(
993 'type' => 'danger',
994 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
995 'msg' => 'mailbox_invalid'
996 );
997 return false;
998 }
999 if (empty($_data['local_part'])) {
1000 $_SESSION['return'][] = array(
1001 'type' => 'danger',
1002 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1003 'msg' => 'mailbox_invalid'
1004 );
1005 return false;
1006 }
1007 $password = $_data['password'];
1008 $password2 = $_data['password2'];
1009 $name = ltrim(rtrim($_data['name'], '>'), '<');
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001010 $tags = $_data['tags'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001011 $quota_m = intval($_data['quota']);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001012 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && $quota_m === 0) {
1013 $_SESSION['return'][] = array(
1014 'type' => 'danger',
1015 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1016 'msg' => 'unlimited_quota_acl'
1017 );
1018 return false;
1019 }
1020 if (empty($name)) {
1021 $name = $local_part;
1022 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001023 if (isset($_data['protocol_access'])) {
1024 $_data['protocol_access'] = (array)$_data['protocol_access'];
1025 $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
1026 $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
1027 $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
1028 $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
1029 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001030 $active = intval($_data['active']);
1031 $force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1032 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1033 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1034 $sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1035 $imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1036 $pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1037 $smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001038 $sieve_access = (isset($_data['sieve_access'])) ? intval($_data['sieve_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001039 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001040 $quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1041 $quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001042 $quota_b = ($quota_m * 1048576);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001043 $mailbox_attrs = json_encode(
1044 array(
1045 'force_pw_update' => strval($force_pw_update),
1046 'tls_enforce_in' => strval($tls_enforce_in),
1047 'tls_enforce_out' => strval($tls_enforce_out),
1048 'sogo_access' => strval($sogo_access),
1049 'imap_access' => strval($imap_access),
1050 'pop3_access' => strval($pop3_access),
1051 'smtp_access' => strval($smtp_access),
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01001052 'sieve_access' => strval($sieve_access),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001053 'relayhost' => strval($relayhost),
1054 'passwd_update' => time(),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001055 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
1056 'quarantine_notification' => strval($quarantine_notification),
1057 'quarantine_category' => strval($quarantine_category)
1058 )
1059 );
1060 if (!is_valid_domain_name($domain)) {
1061 $_SESSION['return'][] = array(
1062 'type' => 'danger',
1063 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1064 'msg' => 'domain_invalid'
1065 );
1066 return false;
1067 }
1068 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1069 $_SESSION['return'][] = array(
1070 'type' => 'danger',
1071 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1072 'msg' => 'access_denied'
1073 );
1074 return false;
1075 }
1076 $stmt = $pdo->prepare("SELECT `mailboxes`, `maxquota`, `quota` FROM `domain`
1077 WHERE `domain` = :domain");
1078 $stmt->execute(array(':domain' => $domain));
1079 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
1080 $stmt = $pdo->prepare("SELECT
1081 COUNT(*) as count,
1082 COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
1083 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001084 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001085 AND `domain` = :domain");
1086 $stmt->execute(array(':domain' => $domain));
1087 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
1088 $stmt = $pdo->prepare("SELECT `local_part` FROM `mailbox` WHERE `local_part` = :local_part and `domain`= :domain");
1089 $stmt->execute(array(':local_part' => $local_part, ':domain' => $domain));
1090 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1091 if ($num_results != 0) {
1092 $_SESSION['return'][] = array(
1093 'type' => 'danger',
1094 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1095 'msg' => array('object_exists', htmlspecialchars($username))
1096 );
1097 return false;
1098 }
1099 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
1100 $stmt->execute(array(':username' => $username));
1101 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1102 if ($num_results != 0) {
1103 $_SESSION['return'][] = array(
1104 'type' => 'danger',
1105 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1106 'msg' => array('is_alias', htmlspecialchars($username))
1107 );
1108 return false;
1109 }
1110 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :username");
1111 $stmt->execute(array(':username' => $username));
1112 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1113 if ($num_results != 0) {
1114 $_SESSION['return'][] = array(
1115 'type' => 'danger',
1116 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1117 'msg' => array('is_spam_alias', htmlspecialchars($username))
1118 );
1119 return false;
1120 }
1121 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1122 $stmt->execute(array(':domain' => $domain));
1123 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1124 if ($num_results == 0) {
1125 $_SESSION['return'][] = array(
1126 'type' => 'danger',
1127 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1128 'msg' => array('domain_not_found', htmlspecialchars($domain))
1129 );
1130 return false;
1131 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001132 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001133 return false;
1134 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001135 $password_hashed = hash_password($password);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001136 if ($MailboxData['count'] >= $DomainData['mailboxes']) {
1137 $_SESSION['return'][] = array(
1138 'type' => 'danger',
1139 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1140 'msg' => array('max_mailbox_exceeded', $MailboxData['count'], $DomainData['mailboxes'])
1141 );
1142 return false;
1143 }
1144 if ($quota_m > $DomainData['maxquota']) {
1145 $_SESSION['return'][] = array(
1146 'type' => 'danger',
1147 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1148 'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota'])
1149 );
1150 return false;
1151 }
1152 if (($MailboxData['quota'] + $quota_m) > $DomainData['quota']) {
1153 $quota_left_m = ($DomainData['quota'] - $MailboxData['quota']);
1154 $_SESSION['return'][] = array(
1155 'type' => 'danger',
1156 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1157 'msg' => array('mailbox_quota_left_exceeded', $quota_left_m)
1158 );
1159 return false;
1160 }
1161 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `active`)
1162 VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :active)");
1163 $stmt->execute(array(
1164 ':username' => $username,
1165 ':password_hashed' => $password_hashed,
1166 ':name' => $name,
1167 ':quota_b' => $quota_b,
1168 ':local_part' => $local_part,
1169 ':domain' => $domain,
1170 ':mailbox_attrs' => $mailbox_attrs,
1171 ':active' => $active
1172 ));
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001173 $stmt = $pdo->prepare("UPDATE `mailbox` SET
1174 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
1175 WHERE `username` = :username");
1176 $stmt->execute(array(
1177 ':username' => $username
1178 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001179 // save tags
1180 foreach($tags as $index => $tag){
1181 if (empty($tag)) continue;
1182 if ($index > $GLOBALS['TAGGING_LIMIT']) {
1183 $_SESSION['return'][] = array(
1184 'type' => 'warning',
1185 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1186 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
1187 );
1188 break;
1189 }
1190 $stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
1191 $stmt->execute(array(
1192 ':username' => $username,
1193 ':tag_name' => $tag,
1194 ));
1195 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001196 $stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
1197 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1198 $stmt->execute(array(':username' => $username));
1199 $stmt = $pdo->prepare("INSERT INTO `quota2replica` (`username`, `bytes`, `messages`)
1200 VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1201 $stmt->execute(array(':username' => $username));
1202 $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
1203 VALUES (:username1, :username2, :domain, :active)");
1204 $stmt->execute(array(
1205 ':username1' => $username,
1206 ':username2' => $username,
1207 ':domain' => $domain,
1208 ':active' => $active
1209 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001210
1211
1212 if (isset($_data['acl'])) {
1213 $_data['acl'] = (array)$_data['acl'];
1214 $_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1215 $_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1216 $_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1217 $_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1218 $_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1219 $_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1220 $_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1221 $_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1222 $_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1223 $_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1224 $_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1225 $_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1226 $_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1227 $_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
1228
1229 $stmt = $pdo->prepare("INSERT INTO `user_acl`
1230 (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
1231 `pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
1232 VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
1233 :pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
1234 $stmt->execute(array(
1235 ':username' => $username,
1236 ':spam_alias' => $_data['spam_alias'],
1237 ':tls_policy' => $_data['tls_policy'],
1238 ':spam_score' => $_data['spam_score'],
1239 ':spam_policy' => $_data['spam_policy'],
1240 ':delimiter_action' => $_data['delimiter_action'],
1241 ':syncjobs' => $_data['syncjobs'],
1242 ':eas_reset' => $_data['eas_reset'],
1243 ':sogo_profile_reset' => $_data['sogo_profile_reset'],
1244 ':pushover' => $_data['pushover'],
1245 ':quarantine' => $_data['quarantine'],
1246 ':quarantine_attachments' => $_data['quarantine_attachments'],
1247 ':quarantine_notification' => $_data['quarantine_notification'],
1248 ':quarantine_category' => $_data['quarantine_category'],
1249 ':app_passwds' => $_data['app_passwds']
1250 ));
1251 }
1252 else {
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001253 $stmt = $pdo->prepare("INSERT INTO `user_acl`
1254 (`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
1255 `pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`)
1256 VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
1257 :pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds) ");
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001258 $stmt->execute(array(
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001259 ':username' => $username,
1260 ':spam_alias' => 0,
1261 ':tls_policy' => 0,
1262 ':spam_score' => 0,
1263 ':spam_policy' => 0,
1264 ':delimiter_action' => 0,
1265 ':syncjobs' => 0,
1266 ':eas_reset' => 0,
1267 ':sogo_profile_reset' => 0,
1268 ':pushover' => 0,
1269 ':quarantine' => 0,
1270 ':quarantine_attachments' => 0,
1271 ':quarantine_notification' => 0,
1272 ':quarantine_category' => 0,
1273 ':app_passwds' => 0
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001274 ));
1275 }
1276
1277 if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
1278 ratelimit('edit', 'mailbox', array(
1279 'object' => $username,
1280 'rl_frame' => $_data['rl_frame'],
1281 'rl_value' => $_data['rl_value']
1282 ));
1283 }
1284
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001285 update_sogo_static_view($username);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001286 $_SESSION['return'][] = array(
1287 'type' => 'success',
1288 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1289 'msg' => array('mailbox_added', htmlspecialchars($username))
1290 );
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001291 return true;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001292 break;
1293 case 'resource':
1294 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1295 $description = $_data['description'];
1296 $local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
1297 $name = $local_part . '@' . $domain;
1298 $kind = $_data['kind'];
1299 $multiple_bookings = intval($_data['multiple_bookings']);
1300 $active = intval($_data['active']);
1301 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
1302 $_SESSION['return'][] = array(
1303 'type' => 'danger',
1304 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1305 'msg' => 'resource_invalid'
1306 );
1307 return false;
1308 }
1309 if (empty($description)) {
1310 $_SESSION['return'][] = array(
1311 'type' => 'danger',
1312 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1313 'msg' => 'description_invalid'
1314 );
1315 return false;
1316 }
1317 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
1318 $multiple_bookings = -1;
1319 }
1320 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
1321 $_SESSION['return'][] = array(
1322 'type' => 'danger',
1323 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1324 'msg' => 'resource_invalid'
1325 );
1326 return false;
1327 }
1328 if (!is_valid_domain_name($domain)) {
1329 $_SESSION['return'][] = array(
1330 'type' => 'danger',
1331 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1332 'msg' => 'domain_invalid'
1333 );
1334 return false;
1335 }
1336 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1337 $_SESSION['return'][] = array(
1338 'type' => 'danger',
1339 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1340 'msg' => 'access_denied'
1341 );
1342 return false;
1343 }
1344 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
1345 $stmt->execute(array(':name' => $name));
1346 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1347 if ($num_results != 0) {
1348 $_SESSION['return'][] = array(
1349 'type' => 'danger',
1350 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1351 'msg' => array('object_exists', htmlspecialchars($name))
1352 );
1353 return false;
1354 }
1355 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
1356 $stmt->execute(array(':name' => $name));
1357 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1358 if ($num_results != 0) {
1359 $_SESSION['return'][] = array(
1360 'type' => 'danger',
1361 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1362 'msg' => array('is_alias', htmlspecialchars($name))
1363 );
1364 return false;
1365 }
1366 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
1367 $stmt->execute(array(':name' => $name));
1368 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1369 if ($num_results != 0) {
1370 $_SESSION['return'][] = array(
1371 'type' => 'danger',
1372 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1373 'msg' => array('is_spam_alias', htmlspecialchars($name))
1374 );
1375 return false;
1376 }
1377 $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1378 $stmt->execute(array(':domain' => $domain));
1379 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1380 if ($num_results == 0) {
1381 $_SESSION['return'][] = array(
1382 'type' => 'danger',
1383 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1384 'msg' => array('domain_not_found', htmlspecialchars($domain))
1385 );
1386 return false;
1387 }
1388 $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`)
1389 VALUES (:name, 'RESOURCE', :description, 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
1390 $stmt->execute(array(
1391 ':name' => $name,
1392 ':description' => $description,
1393 ':local_part' => $local_part,
1394 ':domain' => $domain,
1395 ':active' => $active,
1396 ':kind' => $kind,
1397 ':multiple_bookings' => $multiple_bookings
1398 ));
1399 $_SESSION['return'][] = array(
1400 'type' => 'success',
1401 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1402 'msg' => array('resource_added', htmlspecialchars($name))
1403 );
1404 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001405 case 'domain_templates':
1406 if ($_SESSION['mailcow_cc_role'] != "admin") {
1407 $_SESSION['return'][] = array(
1408 'type' => 'danger',
1409 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1410 'msg' => 'access_denied'
1411 );
1412 return false;
1413 }
1414 if (empty($_data["template"])){
1415 $_SESSION['return'][] = array(
1416 'type' => 'danger',
1417 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1418 'msg' => 'template_name_invalid'
1419 );
1420 return false;
1421 }
1422
1423 // check if template name exists, return false
1424 $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1425 $stmt->execute(array(
1426 ":type" => "domain",
1427 ":template" => $_data["template"]
1428 ));
1429 $row = $stmt->fetch(PDO::FETCH_ASSOC);
1430
1431 if (!empty($row)){
1432 $_SESSION['return'][] = array(
1433 'type' => 'danger',
1434 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1435 'msg' => array('template_exists', $_data["template"])
1436 );
1437 return false;
1438 }
1439
1440 // check attributes
1441 $attr = array();
1442 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1443 $attr['max_num_aliases_for_domain'] = (!empty($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 400;
1444 $attr['max_num_mboxes_for_domain'] = (!empty($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 10;
1445 $attr['def_quota_for_mbox'] = (!empty($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 3072 * 1048576;
1446 $attr['max_quota_for_mbox'] = (!empty($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 10240 * 1048576;
1447 $attr['max_quota_for_domain'] = (!empty($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 10240 * 1048576;
1448 $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1449 $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1450 $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
1451 $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
1452 $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
1453 $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
1454 $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
1455 $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
1456 $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
1457
1458 // save template
1459 $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1460 VALUES (:type, :template, :attributes)");
1461 $stmt->execute(array(
1462 ":type" => "domain",
1463 ":template" => $_data["template"],
1464 ":attributes" => json_encode($attr)
1465 ));
1466
1467 // success
1468 $_SESSION['return'][] = array(
1469 'type' => 'success',
1470 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1471 'msg' => array('template_added', $_data["template"])
1472 );
1473 return true;
1474 break;
1475 case 'mailbox_templates':
1476 if ($_SESSION['mailcow_cc_role'] != "admin") {
1477 $_SESSION['return'][] = array(
1478 'type' => 'danger',
1479 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1480 'msg' => 'access_denied'
1481 );
1482 return false;
1483 }
1484 if (empty($_data["template"])){
1485 $_SESSION['return'][] = array(
1486 'type' => 'danger',
1487 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1488 'msg' => 'template_name_invalid'
1489 );
1490 return false;
1491 }
1492
1493 // check if template name exists, return false
1494 $stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1495 $stmt->execute(array(
1496 ":type" => "mailbox",
1497 ":template" => $_data["template"]
1498 ));
1499 $row = $stmt->fetch(PDO::FETCH_ASSOC);
1500 if (!empty($row)){
1501 $_SESSION['return'][] = array(
1502 'type' => 'danger',
1503 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1504 'msg' => array('template_exists', $_data["template"])
1505 );
1506 return false;
1507 }
1508
1509
1510 // check attributes
1511 $attr = array();
1512 $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
1513 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1514 $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1515 $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
1516 $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1517 $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1518 $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1519 $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1520 $attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
1521 $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1522 $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1523 if (isset($_data['protocol_access'])) {
1524 $_data['protocol_access'] = (array)$_data['protocol_access'];
1525 $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1526 $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1527 $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
1528 $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
1529 }
1530 else {
1531 $attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1532 $attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1533 $attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
1534 $attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
1535 }
1536 if (isset($_data['acl'])) {
1537 $_data['acl'] = (array)$_data['acl'];
1538 $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1539 $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1540 $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1541 $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1542 $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1543 $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1544 $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1545 $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1546 $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1547 $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1548 $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1549 $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1550 $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1551 $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
1552 } else {
1553 $_data['acl'] = (array)$_data['acl'];
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001554 $attr['acl_spam_alias'] = 0;
1555 $attr['acl_tls_policy'] = 0;
1556 $attr['acl_spam_score'] = 0;
1557 $attr['acl_spam_policy'] = 0;
1558 $attr['acl_delimiter_action'] = 0;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001559 $attr['acl_syncjobs'] = 0;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001560 $attr['acl_eas_reset'] = 0;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001561 $attr['acl_sogo_profile_reset'] = 0;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01001562 $attr['acl_pushover'] = 0;
1563 $attr['acl_quarantine'] = 0;
1564 $attr['acl_quarantine_attachments'] = 0;
1565 $attr['acl_quarantine_notification'] = 0;
1566 $attr['acl_quarantine_category'] = 0;
1567 $attr['acl_app_passwds'] = 0;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001568 }
1569
1570
1571
1572 // save template
1573 $stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1574 VALUES (:type, :template, :attributes)");
1575 $stmt->execute(array(
1576 ":type" => "mailbox",
1577 ":template" => $_data["template"],
1578 ":attributes" => json_encode($attr)
1579 ));
1580
1581 // success
1582 $_SESSION['return'][] = array(
1583 'type' => 'success',
1584 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1585 'msg' => array('template_added', $_data["template"])
1586 );
1587 return true;
1588 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001589 }
1590 break;
1591 case 'edit':
1592 switch ($_type) {
1593 case 'alias_domain':
1594 $alias_domains = (array)$_data['alias_domain'];
1595 foreach ($alias_domains as $alias_domain) {
1596 $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
1597 $is_now = mailbox('get', 'alias_domain_details', $alias_domain);
1598 if (!empty($is_now)) {
1599 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1600 $target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46) : $is_now['target_domain'];
1601 }
1602 else {
1603 $_SESSION['return'][] = array(
1604 'type' => 'danger',
1605 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1606 'msg' => array('alias_domain_invalid', htmlspecialchars($alias_domain))
1607 );
1608 continue;
1609 }
1610 if (!is_valid_domain_name($target_domain)) {
1611 $_SESSION['return'][] = array(
1612 'type' => 'danger',
1613 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1614 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1615 );
1616 continue;
1617 }
1618 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
1619 $_SESSION['return'][] = array(
1620 'type' => 'danger',
1621 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1622 'msg' => 'access_denied'
1623 );
1624 continue;
1625 }
1626 if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) {
1627 $_SESSION['return'][] = array(
1628 'type' => 'danger',
1629 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1630 'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1631 );
1632 continue;
1633 }
1634 $stmt = $pdo->prepare("UPDATE `alias_domain` SET
1635 `target_domain` = :target_domain,
1636 `active` = :active
1637 WHERE `alias_domain` = :alias_domain");
1638 $stmt->execute(array(
1639 ':alias_domain' => $alias_domain,
1640 ':target_domain' => $target_domain,
1641 ':active' => $active
1642 ));
1643 $_SESSION['return'][] = array(
1644 'type' => 'success',
1645 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1646 'msg' => array('aliasd_modified', htmlspecialchars($alias_domain))
1647 );
1648 }
1649 break;
1650 case 'tls_policy':
1651 if (!is_array($_data['username'])) {
1652 $usernames = array();
1653 $usernames[] = $_data['username'];
1654 }
1655 else {
1656 $usernames = $_data['username'];
1657 }
1658 if (!isset($_SESSION['acl']['tls_policy']) || $_SESSION['acl']['tls_policy'] != "1" ) {
1659 $_SESSION['return'][] = array(
1660 'type' => 'danger',
1661 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1662 'msg' => 'access_denied'
1663 );
1664 return false;
1665 }
1666 foreach ($usernames as $username) {
1667 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1668 $_SESSION['return'][] = array(
1669 'type' => 'danger',
1670 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1671 'msg' => 'access_denied'
1672 );
1673 continue;
1674 }
1675 $is_now = mailbox('get', 'tls_policy', $username);
1676 if (!empty($is_now)) {
1677 $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
1678 $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
1679 }
1680 else {
1681 $_SESSION['return'][] = array(
1682 'type' => 'danger',
1683 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1684 'msg' => 'access_denied'
1685 );
1686 continue;
1687 }
1688 $stmt = $pdo->prepare("UPDATE `mailbox`
1689 SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_out),
1690 `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_in)
1691 WHERE `username` = :username");
1692 $stmt->execute(array(
1693 ':tls_out' => intval($tls_enforce_out),
1694 ':tls_in' => intval($tls_enforce_in),
1695 ':username' => $username
1696 ));
1697 $_SESSION['return'][] = array(
1698 'type' => 'success',
1699 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1700 'msg' => array('mailbox_modified', $username)
1701 );
1702 }
1703 break;
1704 case 'quarantine_notification':
1705 if (!is_array($_data['username'])) {
1706 $usernames = array();
1707 $usernames[] = $_data['username'];
1708 }
1709 else {
1710 $usernames = $_data['username'];
1711 }
1712 if (!isset($_SESSION['acl']['quarantine_notification']) || $_SESSION['acl']['quarantine_notification'] != "1" ) {
1713 $_SESSION['return'][] = array(
1714 'type' => 'danger',
1715 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1716 'msg' => 'access_denied'
1717 );
1718 return false;
1719 }
1720 foreach ($usernames as $username) {
1721 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1722 $_SESSION['return'][] = array(
1723 'type' => 'danger',
1724 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1725 'msg' => 'access_denied'
1726 );
1727 continue;
1728 }
1729 $is_now = mailbox('get', 'quarantine_notification', $username);
1730 if (!empty($is_now)) {
1731 $quarantine_notification = (isset($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
1732 }
1733 else {
1734 $_SESSION['return'][] = array(
1735 'type' => 'danger',
1736 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1737 'msg' => 'access_denied'
1738 );
1739 continue;
1740 }
1741 if (!in_array($quarantine_notification, array('never', 'hourly', 'daily', 'weekly'))) {
1742 $_SESSION['return'][] = array(
1743 'type' => 'danger',
1744 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1745 'msg' => 'access_denied'
1746 );
1747 continue;
1748 }
1749 $stmt = $pdo->prepare("UPDATE `mailbox`
1750 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', :quarantine_notification)
1751 WHERE `username` = :username");
1752 $stmt->execute(array(
1753 ':quarantine_notification' => $quarantine_notification,
1754 ':username' => $username
1755 ));
1756 $_SESSION['return'][] = array(
1757 'type' => 'success',
1758 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1759 'msg' => array('mailbox_modified', $username)
1760 );
1761 }
1762 break;
1763 case 'quarantine_category':
1764 if (!is_array($_data['username'])) {
1765 $usernames = array();
1766 $usernames[] = $_data['username'];
1767 }
1768 else {
1769 $usernames = $_data['username'];
1770 }
1771 if (!isset($_SESSION['acl']['quarantine_category']) || $_SESSION['acl']['quarantine_category'] != "1" ) {
1772 $_SESSION['return'][] = array(
1773 'type' => 'danger',
1774 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1775 'msg' => 'access_denied'
1776 );
1777 return false;
1778 }
1779 foreach ($usernames as $username) {
1780 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1781 $_SESSION['return'][] = array(
1782 'type' => 'danger',
1783 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1784 'msg' => 'access_denied'
1785 );
1786 continue;
1787 }
1788 $is_now = mailbox('get', 'quarantine_category', $username);
1789 if (!empty($is_now)) {
1790 $quarantine_category = (isset($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
1791 }
1792 else {
1793 $_SESSION['return'][] = array(
1794 'type' => 'danger',
1795 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1796 'msg' => 'access_denied'
1797 );
1798 continue;
1799 }
1800 if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
1801 $_SESSION['return'][] = array(
1802 'type' => 'danger',
1803 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1804 'msg' => 'access_denied'
1805 );
1806 continue;
1807 }
1808 $stmt = $pdo->prepare("UPDATE `mailbox`
1809 SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', :quarantine_category)
1810 WHERE `username` = :username");
1811 $stmt->execute(array(
1812 ':quarantine_category' => $quarantine_category,
1813 ':username' => $username
1814 ));
1815 $_SESSION['return'][] = array(
1816 'type' => 'success',
1817 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1818 'msg' => array('mailbox_modified', $username)
1819 );
1820 }
1821 break;
1822 case 'spam_score':
1823 if (!is_array($_data['username'])) {
1824 $usernames = array();
1825 $usernames[] = $_data['username'];
1826 }
1827 else {
1828 $usernames = $_data['username'];
1829 }
1830 if (!isset($_SESSION['acl']['spam_score']) || $_SESSION['acl']['spam_score'] != "1" ) {
1831 $_SESSION['return'][] = array(
1832 'type' => 'danger',
1833 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1834 'msg' => 'access_denied'
1835 );
1836 return false;
1837 }
1838 foreach ($usernames as $username) {
1839 if ($_data['spam_score'] == "default") {
1840 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1841 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1842 $stmt->execute(array(
1843 ':username' => $username
1844 ));
1845 $_SESSION['return'][] = array(
1846 'type' => 'success',
1847 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1848 'msg' => array('mailbox_modified', $username)
1849 );
1850 continue;
1851 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001852 $lowspamlevel = explode(',', $_data['spam_score'])[0];
1853 $highspamlevel = explode(',', $_data['spam_score'])[1];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001854 if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) {
1855 $_SESSION['return'][] = array(
1856 'type' => 'danger',
1857 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1858 'msg' => 'Invalid spam score, format must be "1,2" where first is low and second is high spam value.'
1859 );
1860 continue;
1861 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001862 if ($lowspamlevel == $highspamlevel) {
1863 $highspamlevel = $highspamlevel + 0.1;
1864 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001865 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
1866 AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
1867 $stmt->execute(array(
1868 ':username' => $username
1869 ));
1870 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1871 VALUES (:username, 'highspamlevel', :highspamlevel)");
1872 $stmt->execute(array(
1873 ':username' => $username,
1874 ':highspamlevel' => $highspamlevel
1875 ));
1876 $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
1877 VALUES (:username, 'lowspamlevel', :lowspamlevel)");
1878 $stmt->execute(array(
1879 ':username' => $username,
1880 ':lowspamlevel' => $lowspamlevel
1881 ));
1882 $_SESSION['return'][] = array(
1883 'type' => 'success',
1884 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1885 'msg' => array('mailbox_modified', $username)
1886 );
1887 }
1888 break;
1889 case 'time_limited_alias':
1890 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
1891 $_SESSION['return'][] = array(
1892 'type' => 'danger',
1893 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1894 'msg' => 'access_denied'
1895 );
1896 return false;
1897 }
1898 if (!is_array($_data['address'])) {
1899 $addresses = array();
1900 $addresses[] = $_data['address'];
1901 }
1902 else {
1903 $addresses = $_data['address'];
1904 }
1905 foreach ($addresses as $address) {
1906 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
1907 $stmt->execute(array(':address' => $address));
1908 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
1909 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
1910 $_SESSION['return'][] = array(
1911 'type' => 'danger',
1912 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1913 'msg' => 'access_denied'
1914 );
1915 continue;
1916 }
1917 if (empty($_data['validity'])) {
1918 continue;
1919 }
1920 $validity = round((int)time() + ($_data['validity'] * 3600));
1921 $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
1922 `address` = :address");
1923 $stmt->execute(array(
1924 ':address' => $address,
1925 ':validity' => $validity
1926 ));
1927 $_SESSION['return'][] = array(
1928 'type' => 'success',
1929 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001930 'msg' => array('mailbox_modified', htmlspecialchars(implode(', ', (array)$usernames)))
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001931 );
1932 }
1933 break;
1934 case 'delimiter_action':
1935 if (!is_array($_data['username'])) {
1936 $usernames = array();
1937 $usernames[] = $_data['username'];
1938 }
1939 else {
1940 $usernames = $_data['username'];
1941 }
1942 if (!isset($_SESSION['acl']['delimiter_action']) || $_SESSION['acl']['delimiter_action'] != "1" ) {
1943 $_SESSION['return'][] = array(
1944 'type' => 'danger',
1945 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1946 'msg' => 'access_denied'
1947 );
1948 return false;
1949 }
1950 foreach ($usernames as $username) {
1951 if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1952 $_SESSION['return'][] = array(
1953 'type' => 'danger',
1954 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1955 'msg' => 'access_denied'
1956 );
1957 continue;
1958 }
1959 if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
1960 try {
1961 $redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
1962 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
1963 }
1964 catch (RedisException $e) {
1965 $_SESSION['return'][] = array(
1966 'type' => 'danger',
1967 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1968 'msg' => array('redis_error', $e)
1969 );
1970 continue;
1971 }
1972 }
1973 else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
1974 try {
1975 $redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
1976 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
1977 }
1978 catch (RedisException $e) {
1979 $_SESSION['return'][] = array(
1980 'type' => 'danger',
1981 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1982 'msg' => array('redis_error', $e)
1983 );
1984 continue;
1985 }
1986 }
1987 else {
1988 try {
1989 $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
1990 $redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
1991 }
1992 catch (RedisException $e) {
1993 $_SESSION['return'][] = array(
1994 'type' => 'danger',
1995 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1996 'msg' => array('redis_error', $e)
1997 );
1998 continue;
1999 }
2000 }
2001 $_SESSION['return'][] = array(
2002 'type' => 'success',
2003 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2004 'msg' => array('mailbox_modified', $username)
2005 );
2006 }
2007 break;
2008 case 'syncjob':
2009 if (!is_array($_data['id'])) {
2010 $ids = array();
2011 $ids[] = $_data['id'];
2012 }
2013 else {
2014 $ids = $_data['id'];
2015 }
2016 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
2017 $_SESSION['return'][] = array(
2018 'type' => 'danger',
2019 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2020 'msg' => 'access_denied'
2021 );
2022 return false;
2023 }
2024 foreach ($ids as $id) {
2025 $is_now = mailbox('get', 'syncjob_details', $id, array('with_password'));
2026 if (!empty($is_now)) {
2027 $username = $is_now['user2'];
2028 $user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1'];
2029 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2030 $last_run = (isset($_data['last_run'])) ? NULL : $is_now['last_run'];
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002031 $success = (isset($_data['success'])) ? NULL : $is_now['success'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002032 $delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
2033 $subscribeall = (isset($_data['subscribeall'])) ? intval($_data['subscribeall']) : $is_now['subscribeall'];
2034 $delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
2035 $delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
2036 $automap = (isset($_data['automap'])) ? intval($_data['automap']) : $is_now['automap'];
2037 $skipcrossduplicates = (isset($_data['skipcrossduplicates'])) ? intval($_data['skipcrossduplicates']) : $is_now['skipcrossduplicates'];
2038 $port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
2039 $password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
2040 $host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
2041 $subfolder2 = (isset($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
2042 $enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
2043 $mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
2044 $exclude = (isset($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
2045 $custom_params = (isset($_data['custom_params'])) ? $_data['custom_params'] : $is_now['custom_params'];
2046 $maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
2047 $maxbytespersecond = (isset($_data['maxbytespersecond']) && $_data['maxbytespersecond'] != "") ? intval($_data['maxbytespersecond']) : $is_now['maxbytespersecond'];
2048 $timeout1 = (isset($_data['timeout1']) && $_data['timeout1'] != "") ? intval($_data['timeout1']) : $is_now['timeout1'];
2049 $timeout2 = (isset($_data['timeout2']) && $_data['timeout2'] != "") ? intval($_data['timeout2']) : $is_now['timeout2'];
2050 }
2051 else {
2052 $_SESSION['return'][] = array(
2053 'type' => 'danger',
2054 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2055 'msg' => 'access_denied'
2056 );
2057 continue;
2058 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002059
2060 // validate custom params
2061 foreach (explode('-', $custom_params) as $param){
2062 if(empty($param)) continue;
2063
2064 // extract option
2065 if (str_contains($param, '=')) $param = explode('=', $param)[0];
2066 else $param = rtrim($param, ' ');
2067 // remove first char if first char is -
2068 if ($param[0] == '-') $param = ltrim($param, $param[0]);
2069
2070 if (str_contains($param, ' ')) {
2071 // bad char
2072 $_SESSION['return'][] = array(
2073 'type' => 'danger',
2074 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2075 'msg' => 'bad character SPACE'
2076 );
2077 return false;
2078 }
2079
2080 // check if param is whitelisted
2081 if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
2082 // bad option
2083 $_SESSION['return'][] = array(
2084 'type' => 'danger',
2085 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2086 'msg' => 'bad option '. $param
2087 );
2088 return false;
2089 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002090 }
2091 if (empty($subfolder2)) {
2092 $subfolder2 = "";
2093 }
2094 if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2095 $maxage = "0";
2096 }
2097 if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2098 $timeout1 = "600";
2099 }
2100 if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2101 $timeout2 = "600";
2102 }
2103 if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
2104 $maxbytespersecond = "0";
2105 }
2106 if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
2107 $_SESSION['return'][] = array(
2108 'type' => 'danger',
2109 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2110 'msg' => 'access_denied'
2111 );
2112 continue;
2113 }
2114 if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
2115 $_SESSION['return'][] = array(
2116 'type' => 'danger',
2117 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2118 'msg' => 'access_denied'
2119 );
2120 continue;
2121 }
2122 if (!is_valid_domain_name($host1)) {
2123 $_SESSION['return'][] = array(
2124 'type' => 'danger',
2125 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2126 'msg' => 'access_denied'
2127 );
2128 continue;
2129 }
2130 if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
2131 $_SESSION['return'][] = array(
2132 'type' => 'danger',
2133 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2134 'msg' => 'access_denied'
2135 );
2136 continue;
2137 }
2138 if (@preg_match("/" . $exclude . "/", null) === false) {
2139 $_SESSION['return'][] = array(
2140 'type' => 'danger',
2141 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2142 'msg' => 'access_denied'
2143 );
2144 continue;
2145 }
2146 $stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1,
2147 `delete2` = :delete2,
2148 `automap` = :automap,
2149 `skipcrossduplicates` = :skipcrossduplicates,
2150 `maxage` = :maxage,
2151 `maxbytespersecond` = :maxbytespersecond,
2152 `subfolder2` = :subfolder2,
2153 `exclude` = :exclude,
2154 `host1` = :host1,
2155 `last_run` = :last_run,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002156 `success` = :success,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002157 `user1` = :user1,
2158 `password1` = :password1,
2159 `mins_interval` = :mins_interval,
2160 `port1` = :port1,
2161 `enc1` = :enc1,
2162 `delete2duplicates` = :delete2duplicates,
2163 `custom_params` = :custom_params,
2164 `timeout1` = :timeout1,
2165 `timeout2` = :timeout2,
2166 `subscribeall` = :subscribeall,
2167 `active` = :active
2168 WHERE `id` = :id");
2169 $stmt->execute(array(
2170 ':delete1' => $delete1,
2171 ':delete2' => $delete2,
2172 ':automap' => $automap,
2173 ':skipcrossduplicates' => $skipcrossduplicates,
2174 ':id' => $id,
2175 ':exclude' => $exclude,
2176 ':maxage' => $maxage,
2177 ':maxbytespersecond' => $maxbytespersecond,
2178 ':subfolder2' => $subfolder2,
2179 ':host1' => $host1,
2180 ':user1' => $user1,
2181 ':password1' => $password1,
2182 ':last_run' => $last_run,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002183 ':success' => $success,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002184 ':mins_interval' => $mins_interval,
2185 ':port1' => $port1,
2186 ':enc1' => $enc1,
2187 ':delete2duplicates' => $delete2duplicates,
2188 ':custom_params' => $custom_params,
2189 ':timeout1' => $timeout1,
2190 ':timeout2' => $timeout2,
2191 ':subscribeall' => $subscribeall,
2192 ':active' => $active,
2193 ));
2194 $_SESSION['return'][] = array(
2195 'type' => 'success',
2196 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2197 'msg' => array('mailbox_modified', $username)
2198 );
2199 }
2200 break;
2201 case 'filter':
2202 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
2203 $_SESSION['return'][] = array(
2204 'type' => 'danger',
2205 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2206 'msg' => 'access_denied'
2207 );
2208 return false;
2209 }
2210 $sieve = new Sieve\SieveParser();
2211 if (!is_array($_data['id'])) {
2212 $ids = array();
2213 $ids[] = $_data['id'];
2214 }
2215 else {
2216 $ids = $_data['id'];
2217 }
2218 foreach ($ids as $id) {
2219 $is_now = mailbox('get', 'filter_details', $id);
2220 if (!empty($is_now)) {
2221 $username = $is_now['username'];
2222 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2223 $script_desc = (!empty($_data['script_desc'])) ? $_data['script_desc'] : $is_now['script_desc'];
2224 $script_data = (!empty($_data['script_data'])) ? $_data['script_data'] : $is_now['script_data'];
2225 $filter_type = (!empty($_data['filter_type'])) ? $_data['filter_type'] : $is_now['filter_type'];
2226 }
2227 else {
2228 $_SESSION['return'][] = array(
2229 'type' => 'danger',
2230 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2231 'msg' => 'access_denied'
2232 );
2233 continue;
2234 }
2235 try {
2236 $sieve->parse($script_data);
2237 }
2238 catch (Exception $e) {
2239 $_SESSION['return'][] = array(
2240 'type' => 'danger',
2241 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2242 'msg' => array('sieve_error', $e->getMessage())
2243 );
2244 continue;
2245 }
2246 if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
2247 $_SESSION['return'][] = array(
2248 'type' => 'danger',
2249 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2250 'msg' => 'filter_type'
2251 );
2252 continue;
2253 }
2254 if ($active == '1') {
2255 $script_name = 'active';
2256 $stmt = $pdo->prepare("UPDATE `sieve_filters`
2257 SET `script_name` = 'inactive'
2258 WHERE `username` = :username
2259 AND `filter_type` = :filter_type");
2260 $stmt->execute(array(
2261 ':username' => $username,
2262 ':filter_type' => $filter_type
2263 ));
2264 }
2265 else {
2266 $script_name = 'inactive';
2267 }
2268 $stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_desc` = :script_desc, `script_data` = :script_data, `script_name` = :script_name, `filter_type` = :filter_type
2269 WHERE `id` = :id");
2270 $stmt->execute(array(
2271 ':script_desc' => $script_desc,
2272 ':script_data' => $script_data,
2273 ':script_name' => $script_name,
2274 ':filter_type' => $filter_type,
2275 ':id' => $id
2276 ));
2277 $_SESSION['return'][] = array(
2278 'type' => 'success',
2279 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2280 'msg' => array('mailbox_modified', $username)
2281 );
2282 }
2283 break;
2284 case 'alias':
2285 if (!is_array($_data['id'])) {
2286 $ids = array();
2287 $ids[] = $_data['id'];
2288 }
2289 else {
2290 $ids = $_data['id'];
2291 }
2292 foreach ($ids as $id) {
2293 $is_now = mailbox('get', 'alias_details', $id);
2294 if (!empty($is_now)) {
2295 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2296 $sogo_visible = (isset($_data['sogo_visible'])) ? intval($_data['sogo_visible']) : $is_now['sogo_visible'];
2297 $goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
2298 $goto_spam = (isset($_data['goto_spam'])) ? intval($_data['goto_spam']) : 0;
2299 $goto_ham = (isset($_data['goto_ham'])) ? intval($_data['goto_ham']) : 0;
2300 $public_comment = (isset($_data['public_comment'])) ? $_data['public_comment'] : $is_now['public_comment'];
2301 $private_comment = (isset($_data['private_comment'])) ? $_data['private_comment'] : $is_now['private_comment'];
2302 $goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
2303 $address = (!empty($_data['address'])) ? $_data['address'] : $is_now['address'];
2304 }
2305 else {
2306 $_SESSION['return'][] = array(
2307 'type' => 'danger',
2308 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2309 'msg' => array('alias_invalid', $address)
2310 );
2311 continue;
2312 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002313 if ($_data['expand_alias'] === true || $_data['expand_alias'] == 1) {
2314 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2315 WHERE `address` = :address
2316 AND `domain` NOT IN (
2317 SELECT `alias_domain` FROM `alias_domain`
2318 )");
2319 $stmt->execute(array(
2320 ':address' => $address,
2321 ));
2322 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2323 if ($num_results == 0) {
2324 $_SESSION['return'][] = array(
2325 'type' => 'warning',
2326 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2327 'msg' => array('is_not_primary_alias', htmlspecialchars($address))
2328 );
2329 continue;
2330 }
2331 $stmt = $pdo->prepare("SELECT `goto`, GROUP_CONCAT(CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`)) AS `missing_alias`
2332 FROM `alias` JOIN `alias_domain` ON `alias_domain`.`target_domain` = `alias`.`domain`
2333 WHERE CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`) NOT IN (
2334 SELECT `address` FROM `alias` WHERE `address` != `goto`
2335 )
2336 AND `alias`.`address` NOT IN (
2337 SELECT `address` FROM `alias` WHERE `address` = `goto`
2338 )
2339 AND `address` = :address ;");
2340 $stmt->execute(array(
2341 ':address' => $address
2342 ));
2343 $missing_aliases = $stmt->fetch(PDO::FETCH_ASSOC);
2344 if (!empty($missing_aliases['missing_alias'])) {
2345 mailbox('add', 'alias', array(
2346 'address' => $missing_aliases['missing_alias'],
2347 'goto' => $missing_aliases['goto'],
2348 'sogo_visible' => 1,
2349 'active' => 1
2350 ));
2351 }
2352 $_SESSION['return'][] = array(
2353 'type' => 'success',
2354 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2355 'msg' => array('alias_modified', htmlspecialchars($address))
2356 );
2357 continue;
2358 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002359 $domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2360 if ($is_now['address'] != $address) {
2361 $local_part = strstr($address, '@', true);
2362 $address = $local_part.'@'.$domain;
2363 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2364 $_SESSION['return'][] = array(
2365 'type' => 'danger',
2366 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2367 'msg' => 'access_denied'
2368 );
2369 continue;
2370 }
2371 if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
2372 $_SESSION['return'][] = array(
2373 'type' => 'danger',
2374 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2375 'msg' => array('alias_invalid', $address)
2376 );
2377 continue;
2378 }
2379 if (strtolower($is_now['address']) != strtolower($address)) {
2380 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
2381 WHERE `address`= :address OR `address` IN (
2382 SELECT `username` FROM `mailbox`, `alias_domain`
2383 WHERE (
2384 `alias_domain`.`alias_domain` = :address_d
2385 AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
2386 $stmt->execute(array(
2387 ':address' => $address,
2388 ':address_l' => $local_part,
2389 ':address_d' => $domain
2390 ));
2391 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2392 if ($num_results != 0) {
2393 $_SESSION['return'][] = array(
2394 'type' => 'danger',
2395 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2396 'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
2397 );
2398 continue;
2399 }
2400 }
2401 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
2402 WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
2403 $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
2404 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2405 if ($num_results == 0) {
2406 $_SESSION['return'][] = array(
2407 'type' => 'danger',
2408 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2409 'msg' => array('domain_not_found', htmlspecialchars($domain))
2410 );
2411 continue;
2412 }
2413 $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
2414 WHERE `address`= :address");
2415 $stmt->execute(array(':address' => $address));
2416 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2417 if ($num_results != 0) {
2418 $_SESSION['return'][] = array(
2419 'type' => 'danger',
2420 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2421 'msg' => array('is_spam_alias', htmlspecialchars($address))
2422 );
2423 continue;
2424 }
2425 }
2426 if ($goto_null == "1") {
2427 $goto = "null@localhost";
2428 }
2429 elseif ($goto_spam == "1") {
2430 $goto = "spam@localhost";
2431 }
2432 elseif ($goto_ham == "1") {
2433 $goto = "ham@localhost";
2434 }
2435 else {
2436 $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $goto));
2437 foreach ($gotos as $i => &$goto) {
2438 if (empty($goto)) {
2439 continue;
2440 }
2441 if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) {
2442 $_SESSION['return'][] = array(
2443 'type' => 'danger',
2444 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2445 'msg' => array('goto_invalid', $goto)
2446 );
2447 unset($gotos[$i]);
2448 continue;
2449 }
2450 if ($goto == $address) {
2451 $_SESSION['return'][] = array(
2452 'type' => 'danger',
2453 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2454 'msg' => 'alias_goto_identical'
2455 );
2456 unset($gotos[$i]);
2457 continue;
2458 }
2459 // Delete from sender_acl to prevent duplicates
2460 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE
2461 `logged_in_as` = :goto AND
2462 `send_as` = :address");
2463 $stmt->execute(array(
2464 ':goto' => $goto,
2465 ':address' => $address
2466 ));
2467 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002468 $gotos = array_unique($gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002469 $gotos = array_filter($gotos);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002470 $goto = implode(",", (array)$gotos);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002471 }
2472 if (!empty($goto)) {
2473 $stmt = $pdo->prepare("UPDATE `alias` SET
2474 `address` = :address,
2475 `public_comment` = :public_comment,
2476 `private_comment` = :private_comment,
2477 `domain` = :domain,
2478 `goto` = :goto,
2479 `sogo_visible`= :sogo_visible,
2480 `active`= :active
2481 WHERE `id` = :id");
2482 $stmt->execute(array(
2483 ':address' => $address,
2484 ':public_comment' => $public_comment,
2485 ':private_comment' => $private_comment,
2486 ':domain' => $domain,
2487 ':goto' => $goto,
2488 ':sogo_visible' => $sogo_visible,
2489 ':active' => $active,
2490 ':id' => $is_now['id']
2491 ));
2492 }
2493 $_SESSION['return'][] = array(
2494 'type' => 'success',
2495 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2496 'msg' => array('alias_modified', htmlspecialchars($address))
2497 );
2498 }
2499 break;
2500 case 'domain':
2501 if (!is_array($_data['domain'])) {
2502 $domains = array();
2503 $domains[] = $_data['domain'];
2504 }
2505 else {
2506 $domains = $_data['domain'];
2507 }
2508 foreach ($domains as $domain) {
2509 $domain = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
2510 if (!is_valid_domain_name($domain)) {
2511 $_SESSION['return'][] = array(
2512 'type' => 'danger',
2513 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2514 'msg' => 'domain_invalid'
2515 );
2516 continue;
2517 }
2518 if ($_SESSION['mailcow_cc_role'] == "domainadmin" &&
2519 hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2520 $is_now = mailbox('get', 'domain_details', $domain);
2521 if (!empty($is_now)) {
2522 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2523 $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 +02002524 (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002525 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002526 }
2527 else {
2528 $_SESSION['return'][] = array(
2529 'type' => 'danger',
2530 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2531 'msg' => 'domain_invalid'
2532 );
2533 continue;
2534 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002535
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002536 $stmt = $pdo->prepare("UPDATE `domain` SET
2537 `description` = :description,
2538 `gal` = :gal
2539 WHERE `domain` = :domain");
2540 $stmt->execute(array(
2541 ':description' => $description,
2542 ':gal' => $gal,
2543 ':domain' => $domain
2544 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002545 // save tags
2546 foreach($tags as $index => $tag){
2547 if (empty($tag)) continue;
2548 if ($index > $GLOBALS['TAGGING_LIMIT']) {
2549 $_SESSION['return'][] = array(
2550 'type' => 'warning',
2551 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2552 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
2553 );
2554 break;
2555 }
2556 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
2557 $stmt->execute(array(
2558 ':domain' => $domain,
2559 ':tag_name' => $tag,
2560 ));
2561 }
2562
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002563 $_SESSION['return'][] = array(
2564 'type' => 'success',
2565 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2566 'msg' => array('domain_modified', htmlspecialchars($domain))
2567 );
2568 }
2569 elseif ($_SESSION['mailcow_cc_role'] == "admin") {
2570 $is_now = mailbox('get', 'domain_details', $domain);
2571 if (!empty($is_now)) {
2572 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2573 $backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx'];
2574 $gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2575 $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients'];
2576 $relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $is_now['relay_unknown_only'];
2577 $relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : $is_now['relayhost'];
2578 $aliases = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain'];
2579 $mailboxes = (isset($_data['mailboxes']) && $_data['mailboxes'] != '') ? intval($_data['mailboxes']) : $is_now['max_num_mboxes_for_domain'];
2580 $defquota = (isset($_data['defquota']) && $_data['defquota'] != '') ? intval($_data['defquota']) : ($is_now['def_quota_for_mbox'] / 1048576);
2581 $maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
2582 $quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
2583 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002584 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002585 if ($relay_all_recipients == '1') {
2586 $backupmx = '1';
2587 }
2588 if ($relay_unknown_only == '1') {
2589 $backupmx = '1';
2590 $relay_all_recipients = '1';
2591 }
2592 }
2593 else {
2594 $_SESSION['return'][] = array(
2595 'type' => 'danger',
2596 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2597 'msg' => 'domain_invalid'
2598 );
2599 continue;
2600 }
2601 // todo: should be using api here
2602 $stmt = $pdo->prepare("SELECT
2603 COUNT(*) AS count,
2604 MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
2605 COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
2606 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002607 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002608 AND domain = :domain");
2609 $stmt->execute(array(':domain' => $domain));
2610 $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
2611 // todo: should be using api here
2612 $stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
2613 WHERE domain = :domain
2614 AND address NOT IN (
2615 SELECT `username` FROM `mailbox`
2616 )");
2617 $stmt->execute(array(':domain' => $domain));
2618 $AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
2619 if ($defquota > $maxquota) {
2620 $_SESSION['return'][] = array(
2621 'type' => 'danger',
2622 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2623 'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
2624 );
2625 continue;
2626 }
2627 if ($defquota == "0" || empty($defquota)) {
2628 $_SESSION['return'][] = array(
2629 'type' => 'danger',
2630 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2631 'msg' => 'defquota_empty'
2632 );
2633 continue;
2634 }
2635 if ($maxquota > $quota) {
2636 $_SESSION['return'][] = array(
2637 'type' => 'danger',
2638 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2639 'msg' => 'mailbox_quota_exceeds_domain_quota'
2640 );
2641 continue;
2642 }
2643 if ($maxquota == "0" || empty($maxquota)) {
2644 $_SESSION['return'][] = array(
2645 'type' => 'danger',
2646 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2647 'msg' => 'maxquota_empty'
2648 );
2649 continue;
2650 }
2651 if ($MailboxData['biggest_mailbox'] > $maxquota) {
2652 $_SESSION['return'][] = array(
2653 'type' => 'danger',
2654 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2655 'msg' => array('max_quota_in_use', $MailboxData['biggest_mailbox'])
2656 );
2657 continue;
2658 }
2659 if ($MailboxData['quota_all'] > $quota) {
2660 $_SESSION['return'][] = array(
2661 'type' => 'danger',
2662 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2663 'msg' => array('domain_quota_m_in_use', $MailboxData['quota_all'])
2664 );
2665 continue;
2666 }
2667 if ($MailboxData['count'] > $mailboxes) {
2668 $_SESSION['return'][] = array(
2669 'type' => 'danger',
2670 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2671 'msg' => array('mailboxes_in_use', $MailboxData['count'])
2672 );
2673 continue;
2674 }
2675 if ($AliasData['count'] > $aliases) {
2676 $_SESSION['return'][] = array(
2677 'type' => 'danger',
2678 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2679 'msg' => array('aliases_in_use', $AliasData['count'])
2680 );
2681 continue;
2682 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002683
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002684 $stmt = $pdo->prepare("UPDATE `domain` SET
2685 `relay_all_recipients` = :relay_all_recipients,
2686 `relay_unknown_only` = :relay_unknown_only,
2687 `backupmx` = :backupmx,
2688 `gal` = :gal,
2689 `active` = :active,
2690 `quota` = :quota,
2691 `defquota` = :defquota,
2692 `maxquota` = :maxquota,
2693 `relayhost` = :relayhost,
2694 `mailboxes` = :mailboxes,
2695 `aliases` = :aliases,
2696 `description` = :description
2697 WHERE `domain` = :domain");
2698 $stmt->execute(array(
2699 ':relay_all_recipients' => $relay_all_recipients,
2700 ':relay_unknown_only' => $relay_unknown_only,
2701 ':backupmx' => $backupmx,
2702 ':gal' => $gal,
2703 ':active' => $active,
2704 ':quota' => $quota,
2705 ':defquota' => $defquota,
2706 ':maxquota' => $maxquota,
2707 ':relayhost' => $relayhost,
2708 ':mailboxes' => $mailboxes,
2709 ':aliases' => $aliases,
2710 ':description' => $description,
2711 ':domain' => $domain
2712 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002713 // save tags
2714 foreach($tags as $index => $tag){
2715 if (empty($tag)) continue;
2716 if ($index > $GLOBALS['TAGGING_LIMIT']) {
2717 $_SESSION['return'][] = array(
2718 'type' => 'warning',
2719 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2720 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
2721 );
2722 break;
2723 }
2724 $stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
2725 $stmt->execute(array(
2726 ':domain' => $domain,
2727 ':tag_name' => $tag,
2728 ));
2729 }
2730
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002731 $_SESSION['return'][] = array(
2732 'type' => 'success',
2733 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2734 'msg' => array('domain_modified', htmlspecialchars($domain))
2735 );
2736 }
2737 }
2738 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002739 case 'domain_templates':
2740 if ($_SESSION['mailcow_cc_role'] != "admin") {
2741 $_SESSION['return'][] = array(
2742 'type' => 'danger',
2743 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
2744 'msg' => 'access_denied'
2745 );
2746 return false;
2747 }
2748 if (!is_array($_data['ids'])) {
2749 $ids = array();
2750 $ids[] = $_data['ids'];
2751 }
2752 else {
2753 $ids = $_data['ids'];
2754 }
2755 foreach ($ids as $id) {
2756 $is_now = mailbox("get", "domain_templates", $id);
2757 if (empty($is_now) ||
2758 $is_now["type"] != "domain"){
2759 $_SESSION['return'][] = array(
2760 'type' => 'danger',
2761 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
2762 'msg' => 'template_id_invalid'
2763 );
2764 continue;
2765 }
2766
2767 // check name
2768 if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
2769 // keep template name of Default template
2770 $_data["template"] = $is_now["template"];
2771 }
2772 else {
2773 $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
2774 }
2775 // check attributes
2776 $attr = array();
2777 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
2778 $attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
2779 $attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
2780 $attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
2781 $attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
2782 $attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
2783 $attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
2784 $attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
2785 $attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
2786 $attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
2787 $attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
2788 $attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
2789 $attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
2790 $attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
2791 $attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
2792
2793 // update template
2794 $stmt = $pdo->prepare("UPDATE `templates`
2795 SET `template` = :template, `attributes` = :attributes
2796 WHERE id = :id");
2797 $stmt->execute(array(
2798 ":id" => $id ,
2799 ":template" => $_data["template"] ,
2800 ":attributes" => json_encode($attr)
2801 ));
2802 }
2803
2804
2805 $_SESSION['return'][] = array(
2806 'type' => 'success',
2807 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2808 'msg' => array('template_modified', $_data["template"])
2809 );
2810 return true;
2811 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002812 case 'mailbox':
2813 if (!is_array($_data['username'])) {
2814 $usernames = array();
2815 $usernames[] = $_data['username'];
2816 }
2817 else {
2818 $usernames = $_data['username'];
2819 }
2820 foreach ($usernames as $username) {
2821 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
2822 $_SESSION['return'][] = array(
2823 'type' => 'danger',
2824 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2825 'msg' => array('username_invalid', $username)
2826 );
2827 continue;
2828 }
2829 $is_now = mailbox('get', 'mailbox_details', $username);
2830 if (isset($_data['protocol_access'])) {
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002831 $_data['protocol_access'] = (array)$_data['protocol_access'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002832 $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
2833 $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
2834 $_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01002835 $_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002836 }
2837 if (!empty($is_now)) {
2838 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2839 (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 +01002840 (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 +01002841 (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']);
2842 (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']);
2843 (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 +01002844 (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 +02002845 (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 +01002846 (int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
2847 $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
2848 $domain = $is_now['domain'];
2849 $quota_b = $quota_m * 1048576;
2850 $password = (!empty($_data['password'])) ? $_data['password'] : null;
2851 $password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01002852 $tags = (is_array($_data['tags']) ? $_data['tags'] : array());
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002853 }
2854 else {
2855 $_SESSION['return'][] = array(
2856 'type' => 'danger',
2857 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2858 'msg' => 'access_denied'
2859 );
2860 continue;
2861 }
2862 // if already 0 == ok
2863 if ((!isset($_SESSION['acl']['unlimited_quota']) || $_SESSION['acl']['unlimited_quota'] != "1") && ($quota_m == 0 && $is_now['quota'] != 0)) {
2864 $_SESSION['return'][] = array(
2865 'type' => 'danger',
2866 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2867 'msg' => 'unlimited_quota_acl'
2868 );
2869 return false;
2870 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002871 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2872 $_SESSION['return'][] = array(
2873 'type' => 'danger',
2874 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2875 'msg' => 'access_denied'
2876 );
2877 continue;
2878 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002879 $DomainData = mailbox('get', 'domain_details', $domain);
2880 if ($quota_m > ($is_now['max_new_quota'] / 1048576)) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002881 $_SESSION['return'][] = array(
2882 'type' => 'danger',
2883 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2884 'msg' => array('mailbox_quota_left_exceeded', ($is_now['max_new_quota'] / 1048576))
2885 );
2886 continue;
2887 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002888 if ($quota_m > $DomainData['max_quota_for_mbox']) {
2889 $_SESSION['return'][] = array(
2890 'type' => 'danger',
2891 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2892 'msg' => array('mailbox_quota_exceeded', $DomainData['max_quota_for_mbox'])
2893 );
2894 continue;
2895 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002896 $extra_acls = array();
2897 if (isset($_data['extended_sender_acl'])) {
2898 if (!isset($_SESSION['acl']['extend_sender_acl']) || $_SESSION['acl']['extend_sender_acl'] != "1" ) {
2899 $_SESSION['return'][] = array(
2900 'type' => 'danger',
2901 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002902 'msg' => 'extended_sender_acl_denied'
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002903 );
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002904 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002905 else {
2906 $extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
2907 foreach ($extra_acls as $i => &$extra_acl) {
2908 if (empty($extra_acl)) {
2909 continue;
2910 }
2911 if (substr($extra_acl, 0, 1) === "@") {
2912 $extra_acl = ltrim($extra_acl, '@');
2913 }
2914 if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002915 $_SESSION['return'][] = array(
2916 'type' => 'danger',
2917 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002918 'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002919 );
2920 unset($extra_acls[$i]);
2921 continue;
2922 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002923 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
2924 if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
2925 $extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2926 if (in_array($extra_acl_domain, $domains)) {
2927 $_SESSION['return'][] = array(
2928 'type' => 'danger',
2929 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2930 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2931 );
2932 unset($extra_acls[$i]);
2933 continue;
2934 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002935 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002936 else {
2937 if (in_array($extra_acl, $domains)) {
2938 $_SESSION['return'][] = array(
2939 'type' => 'danger',
2940 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2941 'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
2942 );
2943 unset($extra_acls[$i]);
2944 continue;
2945 }
2946 $extra_acl = '@' . $extra_acl;
2947 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002948 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002949 $extra_acls = array_filter($extra_acls);
2950 $extra_acls = array_values($extra_acls);
2951 $extra_acls = array_unique($extra_acls);
2952 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002953 $stmt->execute(array(
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002954 ':username' => $username
2955 ));
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01002956 foreach ($extra_acls as $sender_acl_external) {
2957 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
2958 VALUES (:sender_acl, :username, 1)");
2959 $stmt->execute(array(
2960 ':sender_acl' => $sender_acl_external,
2961 ':username' => $username
2962 ));
2963 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01002964 }
2965 }
2966 if (isset($_data['sender_acl'])) {
2967 // Get sender_acl items set by admin
2968 $sender_acl_admin = array_merge(
2969 mailbox('get', 'sender_acl_handles', $username)['sender_acl_domains']['ro'],
2970 mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro']
2971 );
2972 // Get sender_acl items from POST array
2973 // Set sender_acl_domain_admin to empty array if sender_acl contains "default" to trigger a reset
2974 // Delete records from sender_acl if sender_acl contains "*" and set to array("*")
2975 $_data['sender_acl'] = (array)$_data['sender_acl'];
2976 if (in_array("*", $_data['sender_acl'])) {
2977 $sender_acl_domain_admin = array('*');
2978 }
2979 elseif (array("default") === $_data['sender_acl']) {
2980 $sender_acl_domain_admin = array();
2981 }
2982 else {
2983 if (array_search('default', $_data['sender_acl']) !== false){
2984 unset($_data['sender_acl'][array_search('default', $_data['sender_acl'])]);
2985 }
2986 $sender_acl_domain_admin = $_data['sender_acl'];
2987 }
2988 if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) {
2989 // Check items in POST array and skip invalid
2990 foreach ($sender_acl_domain_admin as $key => $val) {
2991 // Check for invalid domain or email format or not *
2992 if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@')) && $val != '*') {
2993 $_SESSION['return'][] = array(
2994 'type' => 'danger',
2995 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2996 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
2997 );
2998 unset($sender_acl_domain_admin[$key]);
2999 continue;
3000 }
3001 // Check if user has domain access (if object is domain)
3002 $domain = ltrim($sender_acl_domain_admin[$key], '@');
3003 if (is_valid_domain_name($domain)) {
3004 // Check for- and skip non-mailcow domains
3005 $domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
3006 if (!empty($domains)) {
3007 if (!in_array($domain, $domains)) {
3008 $_SESSION['return'][] = array(
3009 'type' => 'danger',
3010 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3011 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3012 );
3013 unset($sender_acl_domain_admin[$key]);
3014 continue;
3015 }
3016 }
3017 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3018 $_SESSION['return'][] = array(
3019 'type' => 'danger',
3020 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3021 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3022 );
3023 unset($sender_acl_domain_admin[$key]);
3024 continue;
3025 }
3026 }
3027 // Wildcard can only be used if role == admin
3028 if ($val == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
3029 $_SESSION['return'][] = array(
3030 'type' => 'danger',
3031 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3032 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3033 );
3034 unset($sender_acl_domain_admin[$key]);
3035 continue;
3036 }
3037 // Check if user has alias access (if object is email)
3038 if (filter_var($val, FILTER_VALIDATE_EMAIL)) {
3039 if (!hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) {
3040 $_SESSION['return'][] = array(
3041 'type' => 'danger',
3042 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3043 'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3044 );
3045 unset($sender_acl_domain_admin[$key]);
3046 continue;
3047 }
3048 }
3049 }
3050 // Merge both arrays
3051 $sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin);
3052 // If merged array still contains "*", set it as only value
3053 !in_array('*', $sender_acl_merged) ?: $sender_acl_merged = array('*');
3054 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3055 $stmt->execute(array(
3056 ':username' => $username
3057 ));
3058 $fixed_sender_aliases = mailbox('get', 'sender_acl_handles', $username)['fixed_sender_aliases'];
3059 foreach ($sender_acl_merged as $sender_acl) {
3060 $domain = ltrim($sender_acl, '@');
3061 if (is_valid_domain_name($domain)) {
3062 $sender_acl = '@' . $domain;
3063 }
3064 // Don't add if allowed by alias
3065 if (in_array($sender_acl, $fixed_sender_aliases)) {
3066 continue;
3067 }
3068 $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`)
3069 VALUES (:sender_acl, :username)");
3070 $stmt->execute(array(
3071 ':sender_acl' => $sender_acl,
3072 ':username' => $username
3073 ));
3074 }
3075 }
3076 else {
3077 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3078 $stmt->execute(array(
3079 ':username' => $username
3080 ));
3081 }
3082 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003083 if (!empty($password)) {
3084 if (password_check($password, $password2) !== true) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003085 continue;
3086 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003087 $password_hashed = hash_password($password);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003088 $stmt = $pdo->prepare("UPDATE `mailbox` SET
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003089 `password` = :password_hashed,
3090 `attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003091 WHERE `username` = :username");
3092 $stmt->execute(array(
3093 ':password_hashed' => $password_hashed,
3094 ':username' => $username
3095 ));
3096 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003097 // 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 +01003098 $stmt = $pdo->prepare("UPDATE `alias` SET
3099 `active` = :active
3100 WHERE `address` = :address");
3101 $stmt->execute(array(
3102 ':address' => $username,
3103 ':active' => $active
3104 ));
3105 $stmt = $pdo->prepare("UPDATE `mailbox` SET
3106 `active` = :active,
3107 `name`= :name,
3108 `quota` = :quota_b,
3109 `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
3110 `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
3111 `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01003112 `attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003113 `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003114 `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003115 `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access)
3116 WHERE `username` = :username");
3117 $stmt->execute(array(
3118 ':active' => $active,
3119 ':name' => $name,
3120 ':quota_b' => $quota_b,
3121 ':force_pw_update' => $force_pw_update,
3122 ':sogo_access' => $sogo_access,
3123 ':imap_access' => $imap_access,
3124 ':pop3_access' => $pop3_access,
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +01003125 ':sieve_access' => $sieve_access,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003126 ':smtp_access' => $smtp_access,
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003127 ':relayhost' => $relayhost,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003128 ':username' => $username
3129 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003130 // save tags
3131 foreach($tags as $index => $tag){
3132 if (empty($tag)) continue;
3133 if ($index > $GLOBALS['TAGGING_LIMIT']) {
3134 $_SESSION['return'][] = array(
3135 'type' => 'warning',
3136 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3137 'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
3138 );
3139 break;
3140 }
3141 $stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
3142 $stmt->execute(array(
3143 ':username' => $username,
3144 ':tag_name' => $tag,
3145 ));
3146 }
3147
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003148 $_SESSION['return'][] = array(
3149 'type' => 'success',
3150 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3151 'msg' => array('mailbox_modified', $username)
3152 );
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01003153
3154 update_sogo_static_view($username);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003155 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01003156 return true;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003157 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003158 case 'mailbox_templates':
3159 if ($_SESSION['mailcow_cc_role'] != "admin") {
3160 $_SESSION['return'][] = array(
3161 'type' => 'danger',
3162 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3163 'msg' => 'access_denied'
3164 );
3165 return false;
3166 }
3167 if (!is_array($_data['ids'])) {
3168 $ids = array();
3169 $ids[] = $_data['ids'];
3170 }
3171 else {
3172 $ids = $_data['ids'];
3173 }
3174 foreach ($ids as $id) {
3175 $is_now = mailbox("get", "mailbox_templates", $id);
3176 if (empty($is_now) ||
3177 $is_now["type"] != "mailbox"){
3178 $_SESSION['return'][] = array(
3179 'type' => 'danger',
3180 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3181 'msg' => 'template_id_invalid'
3182 );
3183 continue;
3184 }
3185
3186
3187 // check name
3188 if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
3189 // keep template name of Default template
3190 $_data["template"] = $is_now["template"];
3191 }
3192 else {
3193 $_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
3194 }
3195 // check attributes
3196 $attr = array();
3197 $attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
3198 $attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
3199 $attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
3200 $attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
3201 $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
3202 $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
3203 $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
3204 $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
3205 $attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
3206 $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
3207 $attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
3208 if (isset($_data['protocol_access'])) {
3209 $_data['protocol_access'] = (array)$_data['protocol_access'];
3210 $attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
3211 $attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
3212 $attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
3213 $attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
3214 }
3215 else {
3216 foreach ($is_now as $key => $value){
3217 $attr[$key] = $is_now[$key];
3218 }
3219 }
3220 if (isset($_data['acl'])) {
3221 $_data['acl'] = (array)$_data['acl'];
3222 $attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
3223 $attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
3224 $attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
3225 $attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
3226 $attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
3227 $attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
3228 $attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
3229 $attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
3230 $attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
3231 $attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
3232 $attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
3233 $attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
3234 $attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
3235 $attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
3236 } else {
3237 foreach ($is_now as $key => $value){
3238 $attr[$key] = $is_now[$key];
3239 }
3240 }
3241
3242
3243 // update template
3244 $stmt = $pdo->prepare("UPDATE `templates`
3245 SET `template` = :template, `attributes` = :attributes
3246 WHERE id = :id");
3247 $stmt->execute(array(
3248 ":id" => $id ,
3249 ":template" => $_data["template"] ,
3250 ":attributes" => json_encode($attr)
3251 ));
3252 }
3253
3254
3255 $_SESSION['return'][] = array(
3256 'type' => 'success',
3257 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3258 'msg' => array('template_modified', $_data["template"])
3259 );
3260 return true;
3261 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003262 case 'resource':
3263 if (!is_array($_data['name'])) {
3264 $names = array();
3265 $names[] = $_data['name'];
3266 }
3267 else {
3268 $names = $_data['name'];
3269 }
3270 foreach ($names as $name) {
3271 $is_now = mailbox('get', 'resource_details', $name);
3272 if (!empty($is_now)) {
3273 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
3274 $multiple_bookings = (isset($_data['multiple_bookings'])) ? intval($_data['multiple_bookings']) : $is_now['multiple_bookings'];
3275 $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
3276 $kind = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind'];
3277 }
3278 else {
3279 $_SESSION['return'][] = array(
3280 'type' => 'danger',
3281 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3282 'msg' => array('resource_invalid', htmlspecialchars($name))
3283 );
3284 continue;
3285 }
3286 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
3287 $_SESSION['return'][] = array(
3288 'type' => 'danger',
3289 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3290 'msg' => array('resource_invalid', htmlspecialchars($name))
3291 );
3292 continue;
3293 }
3294 if (!isset($multiple_bookings) || $multiple_bookings < -1) {
3295 $multiple_bookings = -1;
3296 }
3297 if (empty($description)) {
3298 $_SESSION['return'][] = array(
3299 'type' => 'danger',
3300 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3301 'msg' => array('description_invalid', htmlspecialchars($name))
3302 );
3303 continue;
3304 }
3305 if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
3306 $_SESSION['return'][] = array(
3307 'type' => 'danger',
3308 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3309 'msg' => array('resource_invalid', htmlspecialchars($name))
3310 );
3311 continue;
3312 }
3313 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
3314 $_SESSION['return'][] = array(
3315 'type' => 'danger',
3316 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3317 'msg' => 'access_denied'
3318 );
3319 continue;
3320 }
3321 $stmt = $pdo->prepare("UPDATE `mailbox` SET
3322 `active` = :active,
3323 `name`= :description,
3324 `kind`= :kind,
3325 `multiple_bookings`= :multiple_bookings
3326 WHERE `username` = :name");
3327 $stmt->execute(array(
3328 ':active' => $active,
3329 ':description' => $description,
3330 ':multiple_bookings' => $multiple_bookings,
3331 ':kind' => $kind,
3332 ':name' => $name
3333 ));
3334 $_SESSION['return'][] = array(
3335 'type' => 'success',
3336 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3337 'msg' => array('resource_modified', htmlspecialchars($name))
3338 );
3339 }
3340 break;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01003341 case 'domain_wide_footer':
3342 $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
3343 if (!is_valid_domain_name($domain)) {
3344 $_SESSION['return'][] = array(
3345 'type' => 'danger',
3346 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3347 'msg' => 'domain_invalid'
3348 );
3349 return false;
3350 }
3351 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3352 $_SESSION['return'][] = array(
3353 'type' => 'danger',
3354 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3355 'msg' => 'access_denied'
3356 );
3357 return false;
3358 }
3359
3360 $footers = array();
3361 $footers['html'] = isset($_data['footer_html']) ? $_data['footer_html'] : '';
3362 $footers['plain'] = isset($_data['footer_plain']) ? $_data['footer_plain'] : '';
3363 try {
3364 $redis->hSet('DOMAIN_WIDE_FOOTER', $domain, json_encode($footers));
3365 }
3366 catch (RedisException $e) {
3367 $_SESSION['return'][] = array(
3368 'type' => 'danger',
3369 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3370 'msg' => array('redis_error', $e)
3371 );
3372 return false;
3373 }
3374 $_SESSION['return'][] = array(
3375 'type' => 'success',
3376 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3377 'msg' => array('domain_footer_modified', htmlspecialchars($domain))
3378 );
3379 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003380 }
3381 break;
3382 case 'get':
3383 switch ($_type) {
3384 case 'sender_acl_handles':
3385 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
3386 return false;
3387 }
3388 $data['sender_acl_domains']['ro'] = array();
3389 $data['sender_acl_domains']['rw'] = array();
3390 $data['sender_acl_domains']['selectable'] = array();
3391 $data['sender_acl_addresses']['ro'] = array();
3392 $data['sender_acl_addresses']['rw'] = array();
3393 $data['sender_acl_addresses']['selectable'] = array();
3394 $data['fixed_sender_aliases'] = array();
3395 $data['external_sender_aliases'] = array();
3396 // Fixed addresses
3397 $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
3398 $stmt->execute(array(':goto' => '(^|,)'.$_data.'($|,)'));
3399 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3400 while ($row = array_shift($rows)) {
3401 $data['fixed_sender_aliases'][] = $row['address'];
3402 }
3403 $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias_domain_alias` FROM `mailbox`, `alias_domain`
3404 WHERE `alias_domain`.`target_domain` = `mailbox`.`domain`
3405 AND `mailbox`.`username` = :username");
3406 $stmt->execute(array(':username' => $_data));
3407 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3408 while ($row = array_shift($rows)) {
3409 if (!empty($row['alias_domain_alias'])) {
3410 $data['fixed_sender_aliases'][] = $row['alias_domain_alias'];
3411 }
3412 }
3413 // External addresses
3414 $stmt = $pdo->prepare("SELECT `send_as` as `send_as_external` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '1'");
3415 $stmt->execute(array(':logged_in_as' => $_data));
3416 $exernal_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3417 while ($row = array_shift($exernal_rows)) {
3418 if (!empty($row['send_as_external'])) {
3419 $data['external_sender_aliases'][] = $row['send_as_external'];
3420 }
3421 }
3422 // Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects
3423 // Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted)
3424 $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` = '*')");
3425 $stmt->execute(array(':logged_in_as' => $_data));
3426 $domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3427 while ($domain_row = array_shift($domain_rows)) {
3428 if (is_valid_domain_name($domain_row['send_as']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
3429 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
3430 continue;
3431 }
3432 if (is_valid_domain_name($domain_row['send_as']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
3433 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
3434 continue;
3435 }
3436 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
3437 $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
3438 }
3439 if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
3440 $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
3441 }
3442 }
3443 $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` != '*')");
3444 $stmt->execute(array(':logged_in_as' => $_data));
3445 $address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3446 while ($address_row = array_shift($address_rows)) {
3447 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
3448 $data['sender_acl_addresses']['ro'][] = $address_row['send_as'];
3449 continue;
3450 }
3451 if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
3452 $data['sender_acl_addresses']['rw'][] = $address_row['send_as'];
3453 continue;
3454 }
3455 }
3456 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
3457 WHERE `domain` NOT IN (
3458 SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl`
3459 WHERE `logged_in_as` = :logged_in_as1
3460 AND `external` = '0'
3461 AND `send_as` LIKE '@%')
3462 UNION
3463 SELECT '*' FROM `domain`
3464 WHERE '*' NOT IN (
3465 SELECT `send_as` FROM `sender_acl`
3466 WHERE `logged_in_as` = :logged_in_as2
3467 AND `external` = '0'
3468 )");
3469 $stmt->execute(array(
3470 ':logged_in_as1' => $_data,
3471 ':logged_in_as2' => $_data
3472 ));
3473 $rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
3474 while ($row_domain = array_shift($rows_domain)) {
3475 if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) {
3476 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
3477 continue;
3478 }
3479 if ($row_domain['domain'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
3480 $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
3481 continue;
3482 }
3483 }
3484 $stmt = $pdo->prepare("SELECT `address` FROM `alias`
3485 WHERE `goto` != :goto
3486 AND `address` NOT IN (
3487 SELECT `send_as` FROM `sender_acl`
3488 WHERE `logged_in_as` = :logged_in_as
3489 AND `external` = '0'
3490 AND `send_as` NOT LIKE '@%')");
3491 $stmt->execute(array(
3492 ':logged_in_as' => $_data,
3493 ':goto' => $_data
3494 ));
3495 $rows_mbox = $stmt->fetchAll(PDO::FETCH_ASSOC);
3496 while ($row = array_shift($rows_mbox)) {
3497 // Aliases are not selectable
3498 if (in_array($row['address'], $data['fixed_sender_aliases'])) {
3499 continue;
3500 }
3501 if (filter_var($row['address'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['address'])) {
3502 $data['sender_acl_addresses']['selectable'][] = $row['address'];
3503 }
3504 }
3505 return $data;
3506 break;
3507 case 'mailboxes':
3508 $mailboxes = array();
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003509 if (isset($_extra) && is_array($_extra) && isset($_data)) {
3510 // get by domain and tags
3511 $tags = is_array($_extra) ? $_extra : array();
3512
3513 $sql = "";
3514 foreach ($tags as $key => $tag) {
3515 $sql = $sql."SELECT DISTINCT `username` FROM `tags_mailbox` WHERE `username` LIKE ? AND `tag_name` LIKE ?"; // distinct, avoid duplicates
3516 if ($key === array_key_last($tags)) break;
3517 $sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
3518 }
3519
3520 // prepend domain to array
3521 $params = array();
3522 foreach ($tags as $key => $val){
3523 array_push($params, '%'.$_data.'%');
3524 array_push($params, '%'.$val.'%');
3525 }
3526 $stmt = $pdo->prepare($sql);
3527 $stmt->execute($params);
3528
3529 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3530 while($row = array_shift($rows)) {
3531 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], explode('@', $row['username'])[1]))
3532 $mailboxes[] = $row['username'];
3533 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003534 }
3535 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003536 // get by domain
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003537 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003538 $stmt->execute(array(
3539 ':domain' => $_data,
3540 ));
3541 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3542 while($row = array_shift($rows)) {
3543 $mailboxes[] = $row['username'];
3544 }
3545 }
3546 else {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003547 $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 +01003548 $stmt->execute(array(
3549 ':username' => $_SESSION['mailcow_cc_username'],
3550 ':role' => $_SESSION['mailcow_cc_role'],
3551 ));
3552 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3553 while($row = array_shift($rows)) {
3554 $mailboxes[] = $row['username'];
3555 }
3556 }
3557 return $mailboxes;
3558 break;
3559 case 'tls_policy':
3560 $attrs = array();
3561 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3562 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3563 return false;
3564 }
3565 }
3566 else {
3567 $_data = $_SESSION['mailcow_cc_username'];
3568 }
3569 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3570 $stmt->execute(array(':username' => $_data));
3571 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3572 $attrs = json_decode($attrs['attributes'], true);
3573 return array(
3574 'tls_enforce_in' => $attrs['tls_enforce_in'],
3575 'tls_enforce_out' => $attrs['tls_enforce_out']
3576 );
3577 break;
3578 case 'quarantine_notification':
3579 $attrs = array();
3580 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3581 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3582 return false;
3583 }
3584 }
3585 else {
3586 $_data = $_SESSION['mailcow_cc_username'];
3587 }
3588 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3589 $stmt->execute(array(':username' => $_data));
3590 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3591 $attrs = json_decode($attrs['attributes'], true);
3592 return $attrs['quarantine_notification'];
3593 break;
3594 case 'quarantine_category':
3595 $attrs = array();
3596 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3597 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3598 return false;
3599 }
3600 }
3601 else {
3602 $_data = $_SESSION['mailcow_cc_username'];
3603 }
3604 $stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
3605 $stmt->execute(array(':username' => $_data));
3606 $attrs = $stmt->fetch(PDO::FETCH_ASSOC);
3607 $attrs = json_decode($attrs['attributes'], true);
3608 return $attrs['quarantine_category'];
3609 break;
3610 case 'filters':
3611 $filters = array();
3612 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3613 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3614 return false;
3615 }
3616 }
3617 else {
3618 $_data = $_SESSION['mailcow_cc_username'];
3619 }
3620 $stmt = $pdo->prepare("SELECT `id` FROM `sieve_filters` WHERE `username` = :username");
3621 $stmt->execute(array(':username' => $_data));
3622 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3623 while($row = array_shift($rows)) {
3624 $filters[] = $row['id'];
3625 }
3626 return $filters;
3627 break;
3628 case 'global_filter_details':
3629 $global_filters = array();
3630 if ($_SESSION['mailcow_cc_role'] != "admin") {
3631 return false;
3632 }
3633 $global_filters['prefilter'] = file_get_contents('/global_sieve/before');
3634 $global_filters['postfilter'] = file_get_contents('/global_sieve/after');
3635 return $global_filters;
3636 break;
3637 case 'filter_details':
3638 $filter_details = array();
3639 if (!is_numeric($_data)) {
3640 return false;
3641 }
3642 $stmt = $pdo->prepare("SELECT CASE `script_name` WHEN 'active' THEN 1 ELSE 0 END AS `active`,
3643 id,
3644 username,
3645 filter_type,
3646 script_data,
3647 script_desc
3648 FROM `sieve_filters`
3649 WHERE `id` = :id");
3650 $stmt->execute(array(':id' => $_data));
3651 $filter_details = $stmt->fetch(PDO::FETCH_ASSOC);
3652 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $filter_details['username'])) {
3653 return false;
3654 }
3655 return $filter_details;
3656 break;
3657 case 'active_user_sieve':
3658 $filter_details = array();
3659 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3660 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3661 return false;
3662 }
3663 }
3664 else {
3665 $_data = $_SESSION['mailcow_cc_username'];
3666 }
3667 $exec_fields = array(
3668 'cmd' => 'sieve',
3669 'task' => 'list',
3670 'username' => $_data
3671 );
3672 $filters = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3673 $filters = array_filter(preg_split("/(\r\n|\n|\r)/",$filters));
3674 foreach ($filters as $filter) {
3675 if (preg_match('/.+ ACTIVE/i', $filter)) {
3676 $exec_fields = array(
3677 'cmd' => 'sieve',
3678 'task' => 'print',
3679 'script_name' => substr($filter, 0, -7),
3680 'username' => $_data
3681 );
3682 $script = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3683 // Remove first line
3684 return preg_replace('/^.+\n/', '', $script);
3685 }
3686 }
3687 return false;
3688 break;
3689 case 'syncjob_details':
3690 $syncjobdetails = array();
3691 if (!is_numeric($_data)) {
3692 return false;
3693 }
3694 if (isset($_extra) && in_array('no_log', $_extra)) {
3695 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("returned_text", "password1")');
3696 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3697 while($field = array_shift($fields)) {
3698 $shown_fields[] = $field['Field'];
3699 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003700 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003701 `active`
3702 FROM `imapsync` WHERE id = :id");
3703 }
3704 elseif (isset($_extra) && in_array('with_password', $_extra)) {
3705 $stmt = $pdo->prepare("SELECT *,
3706 `active`
3707 FROM `imapsync` WHERE id = :id");
3708 }
3709 else {
3710 $field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("password1")');
3711 $fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
3712 while($field = array_shift($fields)) {
3713 $shown_fields[] = $field['Field'];
3714 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003715 $stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003716 `active`
3717 FROM `imapsync` WHERE id = :id");
3718 }
3719 $stmt->execute(array(':id' => $_data));
3720 $syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
3721 if (!empty($syncjobdetails['returned_text'])) {
3722 $syncjobdetails['log'] = $syncjobdetails['returned_text'];
3723 }
3724 else {
3725 $syncjobdetails['log'] = '';
3726 }
3727 unset($syncjobdetails['returned_text']);
3728 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) {
3729 return false;
3730 }
3731 return $syncjobdetails;
3732 break;
3733 case 'syncjobs':
3734 $syncjobdata = array();
3735 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3736 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3737 return false;
3738 }
3739 }
3740 else {
3741 $_data = $_SESSION['mailcow_cc_username'];
3742 }
3743 $stmt = $pdo->prepare("SELECT `id` FROM `imapsync` WHERE `user2` = :username");
3744 $stmt->execute(array(':username' => $_data));
3745 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3746 while($row = array_shift($rows)) {
3747 $syncjobdata[] = $row['id'];
3748 }
3749 return $syncjobdata;
3750 break;
3751 case 'spam_score':
3752 $curl = curl_init();
3753 curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
3754 curl_setopt($curl, CURLOPT_URL,"http://rspamd/actions");
3755 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
3756 $default_actions = curl_exec($curl);
3757 if (!curl_errno($curl)) {
3758 $data_array = json_decode($default_actions, true);
3759 curl_close($curl);
3760 foreach ($data_array as $data) {
3761 if ($data['action'] == 'reject') {
3762 $reject = $data['value'];
3763 continue;
3764 }
3765 elseif ($data['action'] == 'add header') {
3766 $add_header = $data['value'];
3767 continue;
3768 }
3769 }
3770 if (empty($add_header) || empty($reject)) {
3771 // Assume default, set warning
3772 $default = "5, 15";
3773 $_SESSION['return'][] = array(
3774 'type' => 'warning',
3775 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3776 'msg' => 'Could not determine servers default spam score, assuming default'
3777 );
3778 }
3779 else {
3780 $default = $add_header . ', ' . $reject;
3781 }
3782 }
3783 else {
3784 // Assume default, set warning
3785 $default = "5, 15";
3786 $_SESSION['return'][] = array(
3787 'type' => 'warning',
3788 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3789 'msg' => 'Could not determine servers default spam score, assuming default'
3790 );
3791 }
3792 curl_close($curl);
3793 $policydata = array();
3794 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3795 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3796 return false;
3797 }
3798 }
3799 else {
3800 $_data = $_SESSION['mailcow_cc_username'];
3801 }
3802 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
3803 (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
3804 $stmt->execute(array(':username' => $_data));
3805 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
3806 if (empty($num_results)) {
3807 return $default;
3808 }
3809 else {
3810 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'highspamlevel' AND `object` = :username");
3811 $stmt->execute(array(':username' => $_data));
3812 $highspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3813 $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'lowspamlevel' AND `object` = :username");
3814 $stmt->execute(array(':username' => $_data));
3815 $lowspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
3816 return $lowspamlevel['value'].', '.$highspamlevel['value'];
3817 }
3818 break;
3819 case 'time_limited_aliases':
3820 $tladata = array();
3821 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3822 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3823 return false;
3824 }
3825 }
3826 else {
3827 $_data = $_SESSION['mailcow_cc_username'];
3828 }
3829 $stmt = $pdo->prepare("SELECT `address`,
3830 `goto`,
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02003831 `validity`,
3832 `created`,
3833 `modified`
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003834 FROM `spamalias`
3835 WHERE `goto` = :username
3836 AND `validity` >= :unixnow");
3837 $stmt->execute(array(':username' => $_data, ':unixnow' => time()));
3838 $tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
3839 return $tladata;
3840 break;
3841 case 'delimiter_action':
3842 $policydata = array();
3843 if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
3844 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3845 return false;
3846 }
3847 }
3848 else {
3849 $_data = $_SESSION['mailcow_cc_username'];
3850 }
3851 try {
3852 if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
3853 return "subject";
3854 }
3855 elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
3856 return "subfolder";
3857 }
3858 else {
3859 return "none";
3860 }
3861 }
3862 catch (RedisException $e) {
3863 $_SESSION['return'][] = array(
3864 'type' => 'danger',
3865 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3866 'msg' => array('redis_error', $e)
3867 );
3868 return false;
3869 }
3870 break;
3871 case 'resources':
3872 $resources = array();
3873 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3874 return false;
3875 }
3876 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3877 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` = :domain");
3878 $stmt->execute(array(
3879 ':domain' => $_data,
3880 ));
3881 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3882 while($row = array_shift($rows)) {
3883 $resources[] = $row['username'];
3884 }
3885 }
3886 else {
3887 $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");
3888 $stmt->execute(array(
3889 ':username' => $_SESSION['mailcow_cc_username'],
3890 ':role' => $_SESSION['mailcow_cc_role'],
3891 ));
3892 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3893 while($row = array_shift($rows)) {
3894 $resources[] = $row['username'];
3895 }
3896 }
3897 return $resources;
3898 break;
3899 case 'alias_domains':
3900 $aliasdomains = array();
3901 if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3902 return false;
3903 }
3904 elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3905 $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain");
3906 $stmt->execute(array(
3907 ':domain' => $_data,
3908 ));
3909 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3910 while($row = array_shift($rows)) {
3911 $aliasdomains[] = $row['alias_domain'];
3912 }
3913 }
3914 else {
3915 $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");
3916 $stmt->execute(array(
3917 ':username' => $_SESSION['mailcow_cc_username'],
3918 ':role' => $_SESSION['mailcow_cc_role'],
3919 ));
3920 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3921 while($row = array_shift($rows)) {
3922 $aliasdomains[] = $row['alias_domain'];
3923 }
3924 }
3925 return $aliasdomains;
3926 break;
3927 case 'aliases':
3928 $aliases = array();
3929 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
3930 return false;
3931 }
3932 $stmt = $pdo->prepare("SELECT `id` FROM `alias` WHERE `address` != `goto` AND `domain` = :domain");
3933 $stmt->execute(array(
3934 ':domain' => $_data,
3935 ));
3936 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
3937 while($row = array_shift($rows)) {
3938 $aliases[] = $row['id'];
3939 }
3940 return $aliases;
3941 break;
3942 case 'alias_details':
3943 $aliasdata = array();
3944 $stmt = $pdo->prepare("SELECT
3945 `id`,
3946 `domain`,
3947 `goto`,
3948 `address`,
3949 `public_comment`,
3950 `private_comment`,
3951 `active`,
3952 `sogo_visible`,
3953 `created`,
3954 `modified`
3955 FROM `alias`
3956 WHERE (`id` = :id OR `address` = :address) AND `address` != `goto`");
3957 $stmt->execute(array(
3958 ':id' => $_data,
3959 ':address' => $_data,
3960 ));
3961 $row = $stmt->fetch(PDO::FETCH_ASSOC);
3962 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
3963 $stmt->execute(array(
3964 ':domain' => $row['domain'],
3965 ));
3966 $row_alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
3967 if (isset($row_alias_domain['target_domain']) && !empty($row_alias_domain['target_domain'])) {
3968 $aliasdata['in_primary_domain'] = $row_alias_domain['target_domain'];
3969 }
3970 else {
3971 $aliasdata['in_primary_domain'] = "";
3972 }
3973 $aliasdata['id'] = $row['id'];
3974 $aliasdata['domain'] = $row['domain'];
3975 $aliasdata['public_comment'] = $row['public_comment'];
3976 $aliasdata['private_comment'] = $row['private_comment'];
3977 $aliasdata['domain'] = $row['domain'];
3978 $aliasdata['goto'] = $row['goto'];
3979 $aliasdata['address'] = $row['address'];
3980 (!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
3981 $aliasdata['active'] = $row['active'];
3982 $aliasdata['active_int'] = $row['active'];
3983 $aliasdata['sogo_visible'] = $row['sogo_visible'];
3984 $aliasdata['sogo_visible_int'] = $row['sogo_visible'];
3985 $aliasdata['created'] = $row['created'];
3986 $aliasdata['modified'] = $row['modified'];
3987 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
3988 return false;
3989 }
3990 return $aliasdata;
3991 break;
3992 case 'alias_domain_details':
3993 $aliasdomaindata = array();
3994 $rl = ratelimit('get', 'domain', $_data);
3995 $stmt = $pdo->prepare("SELECT
3996 `alias_domain`,
3997 `target_domain`,
3998 `active`,
3999 `created`,
4000 `modified`
4001 FROM `alias_domain`
4002 WHERE `alias_domain` = :aliasdomain");
4003 $stmt->execute(array(
4004 ':aliasdomain' => $_data,
4005 ));
4006 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4007 $stmt = $pdo->prepare("SELECT `backupmx` FROM `domain` WHERE `domain` = :target_domain");
4008 $stmt->execute(array(
4009 ':target_domain' => $row['target_domain']
4010 ));
4011 $row_parent = $stmt->fetch(PDO::FETCH_ASSOC);
4012 $aliasdomaindata['alias_domain'] = $row['alias_domain'];
4013 $aliasdomaindata['parent_is_backupmx'] = $row_parent['backupmx'];
4014 $aliasdomaindata['target_domain'] = $row['target_domain'];
4015 $aliasdomaindata['active'] = $row['active'];
4016 $aliasdomaindata['active_int'] = $row['active'];
4017 $aliasdomaindata['rl'] = $rl;
4018 $aliasdomaindata['created'] = $row['created'];
4019 $aliasdomaindata['modified'] = $row['modified'];
4020 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdomaindata['target_domain'])) {
4021 return false;
4022 }
4023 return $aliasdomaindata;
4024 break;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01004025 case 'shared_aliases':
4026 $shared_aliases = array();
4027 $stmt = $pdo->query("SELECT `address` FROM `alias`
4028 WHERE `goto` REGEXP ','
4029 AND `address` NOT LIKE '@%'
4030 AND `goto` != `address`");
4031 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4032 while($row = array_shift($rows)) {
4033 $domain = explode("@", $row['address'])[1];
4034 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4035 $shared_aliases[] = $row['address'];
4036 }
4037 }
4038
4039 return $shared_aliases;
4040 break;
4041 case 'direct_aliases':
4042 $direct_aliases = array();
4043 $stmt = $pdo->query("SELECT `address` FROM `alias`
4044 WHERE `goto` NOT LIKE '%,%'
4045 AND `address` NOT LIKE '@%'
4046 AND `goto` != `address`");
4047 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4048
4049 while($row = array_shift($rows)) {
4050 $domain = explode("@", $row['address'])[1];
4051 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4052 $direct_aliases[] = $row['address'];
4053 }
4054 }
4055
4056 return $direct_aliases;
4057 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004058 case 'domains':
4059 $domains = array();
4060 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4061 return false;
4062 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004063
4064 if (isset($_extra) && is_array($_extra)){
4065 // get by tags
4066 $tags = is_array($_extra) ? $_extra : array();
4067 // add % as prefix and suffix to every element for relative searching
4068 $tags = array_map(function($x){ return '%'.$x.'%'; }, $tags);
4069 $sql = "";
4070 foreach ($tags as $key => $tag) {
4071 $sql = $sql."SELECT DISTINCT `domain` FROM `tags_domain` WHERE `tag_name` LIKE ?"; // distinct, avoid duplicates
4072 if ($key === array_key_last($tags)) break;
4073 $sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
4074 }
4075 $stmt = $pdo->prepare($sql);
4076 $stmt->execute($tags);
4077
4078 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4079 while($row = array_shift($rows)) {
4080 if ($_SESSION['mailcow_cc_role'] == "admin")
4081 $domains[] = $row['domain'];
4082 elseif (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain']))
4083 $domains[] = $row['domain'];
4084 }
4085 } else {
4086 // get all
4087 $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
4088 WHERE (`domain` IN (
4089 SELECT `domain` from `domain_admins`
4090 WHERE (`active`='1' AND `username` = :username))
4091 )
4092 OR 'admin'= :role");
4093 $stmt->execute(array(
4094 ':username' => $_SESSION['mailcow_cc_username'],
4095 ':role' => $_SESSION['mailcow_cc_role'],
4096 ));
4097 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4098 while($row = array_shift($rows)) {
4099 $domains[] = $row['domain'];
4100 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004101 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004102
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004103 return $domains;
4104 break;
4105 case 'domain_details':
4106 $domaindata = array();
4107 $_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
4108 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4109 return false;
4110 }
4111 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
4112 $stmt->execute(array(
4113 ':domain' => $_data
4114 ));
4115 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4116 if (!empty($row)) {
4117 $_data = $row['target_domain'];
4118 }
4119 $stmt = $pdo->prepare("SELECT
4120 `domain`,
4121 `description`,
4122 `aliases`,
4123 `mailboxes`,
4124 `defquota`,
4125 `maxquota`,
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004126 `created`,
4127 `modified`,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004128 `quota`,
4129 `relayhost`,
4130 `relay_all_recipients`,
4131 `relay_unknown_only`,
4132 `backupmx`,
4133 `gal`,
4134 `active`
4135 FROM `domain` WHERE `domain`= :domain");
4136 $stmt->execute(array(
4137 ':domain' => $_data
4138 ));
4139 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4140 if (empty($row)) {
4141 return false;
4142 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004143 $stmt = $pdo->prepare("SELECT COUNT(`username`) AS `count`,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004144 COALESCE(SUM(`quota`), 0) AS `in_use`
4145 FROM `mailbox`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004146 WHERE (`kind` = '' OR `kind` = NULL)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004147 AND `domain` = :domain");
4148 $stmt->execute(array(':domain' => $row['domain']));
4149 $MailboxDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
4150 $stmt = $pdo->prepare("SELECT SUM(bytes) AS `bytes_total`, SUM(messages) AS `msgs_total` FROM `quota2`
4151 WHERE `username` IN (
4152 SELECT `username` FROM `mailbox`
4153 WHERE `domain` = :domain
4154 );");
4155 $stmt->execute(array(':domain' => $row['domain']));
4156 $SumQuotaInUse = $stmt->fetch(PDO::FETCH_ASSOC);
4157 $rl = ratelimit('get', 'domain', $_data);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004158 $domaindata['max_new_mailbox_quota'] = ($row['quota'] * 1048576) - $MailboxDataDomain['in_use'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004159 if ($domaindata['max_new_mailbox_quota'] > ($row['maxquota'] * 1048576)) {
4160 $domaindata['max_new_mailbox_quota'] = ($row['maxquota'] * 1048576);
4161 }
4162 $domaindata['def_new_mailbox_quota'] = $domaindata['max_new_mailbox_quota'];
4163 if ($domaindata['def_new_mailbox_quota'] > ($row['defquota'] * 1048576)) {
4164 $domaindata['def_new_mailbox_quota'] = ($row['defquota'] * 1048576);
4165 }
4166 $domaindata['quota_used_in_domain'] = $MailboxDataDomain['in_use'];
4167 if (!empty($SumQuotaInUse['bytes_total'])) {
4168 $domaindata['bytes_total'] = $SumQuotaInUse['bytes_total'];
4169 }
4170 else {
4171 $domaindata['bytes_total'] = 0;
4172 }
4173 if (!empty($SumQuotaInUse['msgs_total'])) {
4174 $domaindata['msgs_total'] = $SumQuotaInUse['msgs_total'];
4175 }
4176 else {
4177 $domaindata['msgs_total'] = 0;
4178 }
4179 $domaindata['mboxes_in_domain'] = $MailboxDataDomain['count'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004180 $domaindata['mboxes_left'] = $row['mailboxes'] - $MailboxDataDomain['count'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004181 $domaindata['domain_name'] = $row['domain'];
4182 $domaindata['description'] = $row['description'];
4183 $domaindata['max_num_aliases_for_domain'] = $row['aliases'];
4184 $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
4185 $domaindata['def_quota_for_mbox'] = $row['defquota'] * 1048576;
4186 $domaindata['max_quota_for_mbox'] = $row['maxquota'] * 1048576;
4187 $domaindata['max_quota_for_domain'] = $row['quota'] * 1048576;
4188 $domaindata['relayhost'] = $row['relayhost'];
4189 $domaindata['backupmx'] = $row['backupmx'];
4190 $domaindata['backupmx_int'] = $row['backupmx'];
4191 $domaindata['gal'] = $row['gal'];
4192 $domaindata['gal_int'] = $row['gal'];
4193 $domaindata['rl'] = $rl;
4194 $domaindata['active'] = $row['active'];
4195 $domaindata['active_int'] = $row['active'];
4196 $domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
4197 $domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
4198 $domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
4199 $domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004200 $domaindata['created'] = $row['created'];
4201 $domaindata['modified'] = $row['modified'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004202 $stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004203 WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
4204 AND `address` NOT IN (
4205 SELECT `username` FROM `mailbox`
4206 )");
4207 $stmt->execute(array(
4208 ':domain' => $_data,
4209 ':domain2' => $_data
4210 ));
4211 $AliasDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
4212 (isset($AliasDataDomain['alias_count'])) ? $domaindata['aliases_in_domain'] = $AliasDataDomain['alias_count'] : $domaindata['aliases_in_domain'] = "0";
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004213 $domaindata['aliases_left'] = $row['aliases'] - $AliasDataDomain['alias_count'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004214 if ($_SESSION['mailcow_cc_role'] == "admin")
4215 {
4216 $stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS domain_admins FROM `domain_admins` WHERE `domain` = :domain");
4217 $stmt->execute(array(
4218 ':domain' => $_data
4219 ));
4220 $domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
4221 (isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
4222 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004223 $stmt = $pdo->prepare("SELECT `tag_name`
4224 FROM `tags_domain` WHERE `domain`= :domain");
4225 $stmt->execute(array(
4226 ':domain' => $_data
4227 ));
4228 $tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
4229 while ($tag = array_shift($tags)) {
4230 $domaindata['tags'][] = $tag['tag_name'];
4231 }
4232
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004233 return $domaindata;
4234 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004235 case 'domain_templates':
4236 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4237 return false;
4238 }
4239 $_data = (isset($_data)) ? intval($_data) : null;
4240
4241 if (isset($_data)){
4242 $stmt = $pdo->prepare("SELECT * FROM `templates`
4243 WHERE `id` = :id AND type = :type");
4244 $stmt->execute(array(
4245 ":id" => $_data,
4246 ":type" => "domain"
4247 ));
4248 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4249
4250 if (empty($row)){
4251 return false;
4252 }
4253
4254 $row["attributes"] = json_decode($row["attributes"], true);
4255 return $row;
4256 }
4257 else {
4258 $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'");
4259 $stmt->execute();
4260 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4261
4262 if (empty($rows)){
4263 return false;
4264 }
4265
4266 foreach($rows as $key => $row){
4267 $rows[$key]["attributes"] = json_decode($row["attributes"], true);
4268 }
4269 return $rows;
4270 }
4271 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004272 case 'mailbox_details':
4273 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4274 return false;
4275 }
4276 $mailboxdata = array();
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004277 if (preg_match('/y|yes/i', getenv('MASTER'))) {
4278 $stmt = $pdo->prepare("SELECT
4279 `domain`.`backupmx`,
4280 `mailbox`.`username`,
4281 `mailbox`.`name`,
4282 `mailbox`.`active`,
4283 `mailbox`.`domain`,
4284 `mailbox`.`local_part`,
4285 `mailbox`.`quota`,
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004286 `mailbox`.`created`,
4287 `mailbox`.`modified`,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004288 `quota2`.`bytes`,
4289 `attributes`,
4290 `quota2`.`messages`
4291 FROM `mailbox`, `quota2`, `domain`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004292 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
4293 AND `mailbox`.`username` = `quota2`.`username`
4294 AND `domain`.`domain` = `mailbox`.`domain`
4295 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004296 }
4297 else {
4298 $stmt = $pdo->prepare("SELECT
4299 `domain`.`backupmx`,
4300 `mailbox`.`username`,
4301 `mailbox`.`name`,
4302 `mailbox`.`active`,
4303 `mailbox`.`domain`,
4304 `mailbox`.`local_part`,
4305 `mailbox`.`quota`,
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004306 `mailbox`.`created`,
4307 `mailbox`.`modified`,
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004308 `quota2replica`.`bytes`,
4309 `attributes`,
4310 `quota2replica`.`messages`
4311 FROM `mailbox`, `quota2replica`, `domain`
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004312 WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
4313 AND `mailbox`.`username` = `quota2replica`.`username`
4314 AND `domain`.`domain` = `mailbox`.`domain`
4315 AND `mailbox`.`username` = :mailbox");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004316 }
4317 $stmt->execute(array(
4318 ':mailbox' => $_data,
4319 ));
4320 $row = $stmt->fetch(PDO::FETCH_ASSOC);
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004321
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004322 $mailboxdata['username'] = $row['username'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004323 $mailboxdata['active'] = $row['active'];
4324 $mailboxdata['active_int'] = $row['active'];
4325 $mailboxdata['domain'] = $row['domain'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004326 $mailboxdata['relayhost'] = $row['relayhost'];
4327 $mailboxdata['name'] = $row['name'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004328 $mailboxdata['local_part'] = $row['local_part'];
4329 $mailboxdata['quota'] = $row['quota'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004330 $mailboxdata['messages'] = $row['messages'];
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004331 $mailboxdata['attributes'] = json_decode($row['attributes'], true);
4332 $mailboxdata['quota_used'] = intval($row['bytes']);
4333 $mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004334 $mailboxdata['created'] = $row['created'];
4335 $mailboxdata['modified'] = $row['modified'];
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004336
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004337 if ($mailboxdata['percent_in_use'] === '- ') {
4338 $mailboxdata['percent_class'] = "info";
4339 }
4340 elseif ($mailboxdata['percent_in_use'] >= 90) {
4341 $mailboxdata['percent_class'] = "danger";
4342 }
4343 elseif ($mailboxdata['percent_in_use'] >= 75) {
4344 $mailboxdata['percent_class'] = "warning";
4345 }
4346 else {
4347 $mailboxdata['percent_class'] = "success";
4348 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004349
4350 // Determine last logins
4351 $stmt = $pdo->prepare("SELECT MAX(`datetime`) AS `datetime`, `service` FROM `sasl_log`
4352 WHERE `username` = :mailbox
4353 GROUP BY `service` DESC");
4354 $stmt->execute(array(':mailbox' => $_data));
4355 $SaslLogsData = $stmt->fetchAll(PDO::FETCH_ASSOC);
4356 foreach ($SaslLogsData as $SaslLogs) {
4357 if ($SaslLogs['service'] == 'imap') {
4358 $last_imap_login = strtotime($SaslLogs['datetime']);
4359 }
4360 else if ($SaslLogs['service'] == 'smtp') {
4361 $last_smtp_login = strtotime($SaslLogs['datetime']);
4362 }
4363 else if ($SaslLogs['service'] == 'pop3') {
4364 $last_pop3_login = strtotime($SaslLogs['datetime']);
4365 }
4366 }
4367 if (!isset($last_imap_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4368 $last_imap_login = 0;
4369 }
4370 if (!isset($last_smtp_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4371 $last_smtp_login = 0;
4372 }
4373 if (!isset($last_pop3_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
4374 $last_pop3_login = 0;
4375 }
4376 $mailboxdata['last_imap_login'] = $last_imap_login;
4377 $mailboxdata['last_smtp_login'] = $last_smtp_login;
4378 $mailboxdata['last_pop3_login'] = $last_pop3_login;
4379
4380 if (!isset($_extra) || $_extra != 'reduced') {
4381 $rl = ratelimit('get', 'mailbox', $_data);
4382 $stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
4383 $stmt->execute(array(':domain' => $row['domain']));
4384 $DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
4385
4386 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
4387 $stmt->execute(array(':username' => $_data));
4388 $PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
4389 $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
4390 $stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
4391 $MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
4392 $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
4393 $stmt->execute(array(':address' => $_data, ':unixnow' => time()));
4394 $SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
4395 $mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
4396 $mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
4397 $mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
4398 if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
4399 $mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
4400 }
4401 if (!empty($rl)) {
4402 $mailboxdata['rl'] = $rl;
4403 $mailboxdata['rl_scope'] = 'mailbox';
4404 }
4405 else {
4406 $mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
4407 $mailboxdata['rl_scope'] = 'domain';
4408 }
4409 $mailboxdata['is_relayed'] = $row['backupmx'];
4410 }
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004411 $stmt = $pdo->prepare("SELECT `tag_name`
4412 FROM `tags_mailbox` WHERE `username`= :username");
4413 $stmt->execute(array(
4414 ':username' => $_data
4415 ));
4416 $tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
4417 while ($tag = array_shift($tags)) {
4418 $mailboxdata['tags'][] = $tag['tag_name'];
4419 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004420
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004421 return $mailboxdata;
4422 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004423 case 'mailbox_templates':
4424 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4425 return false;
4426 }
4427 $_data = (isset($_data)) ? intval($_data) : null;
4428
4429 if (isset($_data)){
4430 $stmt = $pdo->prepare("SELECT * FROM `templates`
4431 WHERE `id` = :id AND type = :type");
4432 $stmt->execute(array(
4433 ":id" => $_data,
4434 ":type" => "mailbox"
4435 ));
4436 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4437
4438 if (empty($row)){
4439 return false;
4440 }
4441
4442 $row["attributes"] = json_decode($row["attributes"], true);
4443 return $row;
4444 }
4445 else {
4446 $stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'");
4447 $stmt->execute();
4448 $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4449
4450 if (empty($rows)){
4451 return false;
4452 }
4453
4454 foreach($rows as $key => $row){
4455 $rows[$key]["attributes"] = json_decode($row["attributes"], true);
4456 }
4457 return $rows;
4458 }
4459 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004460 case 'resource_details':
4461 $resourcedata = array();
4462 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4463 return false;
4464 }
4465 $stmt = $pdo->prepare("SELECT
4466 `username`,
4467 `name`,
4468 `kind`,
4469 `multiple_bookings`,
4470 `local_part`,
4471 `active`,
4472 `domain`
4473 FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
4474 $stmt->execute(array(
4475 ':resource' => $_data,
4476 ));
4477 $row = $stmt->fetch(PDO::FETCH_ASSOC);
4478 $resourcedata['name'] = $row['username'];
4479 $resourcedata['kind'] = $row['kind'];
4480 $resourcedata['multiple_bookings'] = $row['multiple_bookings'];
4481 $resourcedata['description'] = $row['name'];
4482 $resourcedata['active'] = $row['active'];
4483 $resourcedata['active_int'] = $row['active'];
4484 $resourcedata['domain'] = $row['domain'];
4485 $resourcedata['local_part'] = $row['local_part'];
4486 if (!isset($resourcedata['domain']) ||
4487 (isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
4488 return false;
4489 }
4490 return $resourcedata;
4491 break;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01004492 case 'domain_wide_footer':
4493 $domain = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
4494 if (!is_valid_domain_name($domain)) {
4495 $_SESSION['return'][] = array(
4496 'type' => 'danger',
4497 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4498 'msg' => 'domain_invalid'
4499 );
4500 return false;
4501 }
4502 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4503 $_SESSION['return'][] = array(
4504 'type' => 'danger',
4505 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4506 'msg' => 'access_denied'
4507 );
4508 return false;
4509 }
4510
4511 try {
4512 $footers = $redis->hGet('DOMAIN_WIDE_FOOTER', $domain);
4513 $footers = json_decode($footers, true);
4514 }
4515 catch (RedisException $e) {
4516 $_SESSION['return'][] = array(
4517 'type' => 'danger',
4518 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4519 'msg' => array('redis_error', $e)
4520 );
4521 return false;
4522 }
4523
4524 return $footers;
4525 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004526 }
4527 break;
4528 case 'delete':
4529 switch ($_type) {
4530 case 'syncjob':
4531 if (!is_array($_data['id'])) {
4532 $ids = array();
4533 $ids[] = $_data['id'];
4534 }
4535 else {
4536 $ids = $_data['id'];
4537 }
4538 if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
4539 $_SESSION['return'][] = array(
4540 'type' => 'danger',
4541 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4542 'msg' => 'access_denied'
4543 );
4544 return false;
4545 }
4546 foreach ($ids as $id) {
4547 if (!is_numeric($id)) {
4548 return false;
4549 }
4550 $stmt = $pdo->prepare("SELECT `user2` FROM `imapsync` WHERE id = :id");
4551 $stmt->execute(array(':id' => $id));
4552 $user2 = $stmt->fetch(PDO::FETCH_ASSOC)['user2'];
4553 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) {
4554 $_SESSION['return'][] = array(
4555 'type' => 'danger',
4556 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4557 'msg' => 'access_denied'
4558 );
4559 continue;
4560 }
4561 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `id`= :id");
4562 $stmt->execute(array(':id' => $id));
4563 $_SESSION['return'][] = array(
4564 'type' => 'success',
4565 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4566 'msg' => array('deleted_syncjob', $id)
4567 );
4568 }
4569 break;
4570 case 'filter':
4571 if (!is_array($_data['id'])) {
4572 $ids = array();
4573 $ids[] = $_data['id'];
4574 }
4575 else {
4576 $ids = $_data['id'];
4577 }
4578 if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
4579 $_SESSION['return'][] = array(
4580 'type' => 'danger',
4581 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4582 'msg' => 'access_denied'
4583 );
4584 return false;
4585 }
4586 foreach ($ids as $id) {
4587 if (!is_numeric($id)) {
4588 continue;
4589 }
4590 $stmt = $pdo->prepare("SELECT `username` FROM `sieve_filters` WHERE id = :id");
4591 $stmt->execute(array(':id' => $id));
4592 $usr = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
4593 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $usr)) {
4594 $_SESSION['return'][] = array(
4595 'type' => 'danger',
4596 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4597 'msg' => 'access_denied'
4598 );
4599 continue;
4600 }
4601 $stmt = $pdo->prepare("DELETE FROM `sieve_filters` WHERE `id`= :id");
4602 $stmt->execute(array(':id' => $id));
4603 $_SESSION['return'][] = array(
4604 'type' => 'success',
4605 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4606 'msg' => array('delete_filter', $id)
4607 );
4608 }
4609 break;
4610 case 'time_limited_alias':
4611 if (!is_array($_data['address'])) {
4612 $addresses = array();
4613 $addresses[] = $_data['address'];
4614 }
4615 else {
4616 $addresses = $_data['address'];
4617 }
4618 if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
4619 $_SESSION['return'][] = array(
4620 'type' => 'danger',
4621 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4622 'msg' => 'access_denied'
4623 );
4624 return false;
4625 }
4626 foreach ($addresses as $address) {
4627 $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
4628 $stmt->execute(array(':address' => $address));
4629 $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
4630 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
4631 $_SESSION['return'][] = array(
4632 'type' => 'danger',
4633 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4634 'msg' => 'access_denied'
4635 );
4636 continue;
4637 }
4638 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username AND `address` = :item");
4639 $stmt->execute(array(
4640 ':username' => $goto,
4641 ':item' => $address
4642 ));
4643 $_SESSION['return'][] = array(
4644 'type' => 'success',
4645 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4646 'msg' => array('mailbox_modified', htmlspecialchars($goto))
4647 );
4648 }
4649 break;
4650 case 'eas_cache':
4651 if (!is_array($_data['username'])) {
4652 $usernames = array();
4653 $usernames[] = $_data['username'];
4654 }
4655 else {
4656 $usernames = $_data['username'];
4657 }
4658 if (!isset($_SESSION['acl']['eas_reset']) || $_SESSION['acl']['eas_reset'] != "1" ) {
4659 $_SESSION['return'][] = array(
4660 'type' => 'danger',
4661 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4662 'msg' => 'access_denied'
4663 );
4664 return false;
4665 }
4666 foreach ($usernames as $username) {
4667 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
4668 $_SESSION['return'][] = array(
4669 'type' => 'danger',
4670 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4671 'msg' => 'access_denied'
4672 );
4673 continue;
4674 }
4675 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4676 $stmt->execute(array(
4677 ':username' => $username
4678 ));
4679 $_SESSION['return'][] = array(
4680 'type' => 'success',
4681 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4682 'msg' => array('eas_reset', htmlspecialchars($username))
4683 );
4684 }
4685 break;
4686 case 'sogo_profile':
4687 if (!is_array($_data['username'])) {
4688 $usernames = array();
4689 $usernames[] = $_data['username'];
4690 }
4691 else {
4692 $usernames = $_data['username'];
4693 }
4694 if (!isset($_SESSION['acl']['sogo_profile_reset']) || $_SESSION['acl']['sogo_profile_reset'] != "1" ) {
4695 $_SESSION['return'][] = array(
4696 'type' => 'danger',
4697 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4698 'msg' => 'access_denied'
4699 );
4700 return false;
4701 }
4702 foreach ($usernames as $username) {
4703 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
4704 $_SESSION['return'][] = array(
4705 'type' => 'danger',
4706 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4707 'msg' => 'access_denied'
4708 );
4709 continue;
4710 }
4711 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
4712 $stmt->execute(array(
4713 ':username' => $username
4714 ));
4715 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
4716 $stmt->execute(array(
4717 ':username' => $username
4718 ));
4719 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
4720 $stmt->execute(array(
4721 ':username' => $username
4722 ));
4723 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
4724 $stmt->execute(array(
4725 ':username' => $username
4726 ));
4727 $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)");
4728 $stmt->execute(array(
4729 ':username' => $username
4730 ));
4731 $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)");
4732 $stmt->execute(array(
4733 ':username' => $username
4734 ));
4735 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
4736 $stmt->execute(array(
4737 ':username' => $username
4738 ));
4739 $_SESSION['return'][] = array(
4740 'type' => 'success',
4741 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4742 'msg' => array('sogo_profile_reset', htmlspecialchars($username))
4743 );
4744 }
4745 break;
4746 case 'domain':
4747 if (!is_array($_data['domain'])) {
4748 $domains = array();
4749 $domains[] = $_data['domain'];
4750 }
4751 else {
4752 $domains = $_data['domain'];
4753 }
4754 if ($_SESSION['mailcow_cc_role'] != "admin") {
4755 $_SESSION['return'][] = array(
4756 'type' => 'danger',
4757 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4758 'msg' => 'access_denied'
4759 );
4760 return false;
4761 }
4762 foreach ($domains as $domain) {
4763 if (!is_valid_domain_name($domain)) {
4764 $_SESSION['return'][] = array(
4765 'type' => 'danger',
4766 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4767 'msg' => 'domain_invalid'
4768 );
4769 continue;
4770 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02004771 $domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004772 $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
4773 WHERE `domain` = :domain");
4774 $stmt->execute(array(':domain' => $domain));
4775 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
4776 if ($num_results != 0 || !empty($num_results)) {
4777 $_SESSION['return'][] = array(
4778 'type' => 'danger',
4779 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4780 'msg' => array('domain_not_empty', $domain)
4781 );
4782 continue;
4783 }
4784 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $domain);
4785 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
4786 if ($maildir_gc['type'] != 'success') {
4787 $_SESSION['return'][] = array(
4788 'type' => 'warning',
4789 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4790 'msg' => 'Could not move mail storage to garbage collector: ' . $maildir_gc['msg']
4791 );
4792 }
4793 $stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
4794 $stmt->execute(array(
4795 ':domain' => $domain,
4796 ));
4797 $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `domain` = :domain");
4798 $stmt->execute(array(
4799 ':domain' => $domain,
4800 ));
4801 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :domain");
4802 $stmt->execute(array(
4803 ':domain' => $domain,
4804 ));
4805 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `target_domain` = :domain");
4806 $stmt->execute(array(
4807 ':domain' => $domain,
4808 ));
4809 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `domain` = :domain");
4810 $stmt->execute(array(
4811 ':domain' => $domain,
4812 ));
4813 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` LIKE :domain");
4814 $stmt->execute(array(
4815 ':domain' => '%@'.$domain,
4816 ));
4817 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain");
4818 $stmt->execute(array(
4819 ':domain' => '%@'.$domain,
4820 ));
4821 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` LIKE :domain");
4822 $stmt->execute(array(
4823 ':domain' => '%@'.$domain,
4824 ));
4825 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` LIKE :domain");
4826 $stmt->execute(array(
4827 ':domain' => '%@'.$domain,
4828 ));
4829 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
4830 $stmt->execute(array(
4831 ':domain' => '%@'.$domain,
4832 ));
4833 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
4834 $stmt->execute(array(
4835 ':domain' => $domain,
4836 ));
4837 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
4838 $stmt->execute(array(
4839 ':domain' => $domain,
4840 ));
4841 $stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
4842 $stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
4843 try {
4844 $redis->hDel('DOMAIN_MAP', $domain);
4845 $redis->hDel('RL_VALUE', $domain);
4846 }
4847 catch (RedisException $e) {
4848 $_SESSION['return'][] = array(
4849 'type' => 'danger',
4850 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4851 'msg' => array('redis_error', $e)
4852 );
4853 continue;
4854 }
4855 $_SESSION['return'][] = array(
4856 'type' => 'success',
4857 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4858 'msg' => array('domain_removed', htmlspecialchars($domain))
4859 );
4860 }
4861 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004862 case 'domain_templates':
4863 if ($_SESSION['mailcow_cc_role'] != "admin") {
4864 $_SESSION['return'][] = array(
4865 'type' => 'danger',
4866 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4867 'msg' => 'access_denied'
4868 );
4869 return false;
4870 }
4871 if (!is_array($_data['ids'])) {
4872 $ids = array();
4873 $ids[] = $_data['ids'];
4874 }
4875 else {
4876 $ids = $_data['ids'];
4877 }
4878
4879
4880 foreach ($ids as $id) {
4881 // delete template
4882 $stmt = $pdo->prepare("DELETE FROM `templates`
4883 WHERE id = :id AND type = :type AND NOT template = :template");
4884 $stmt->execute(array(
4885 ":id" => $id,
4886 ":type" => "domain",
4887 ":template" => "Default"
4888 ));
4889
4890 $_SESSION['return'][] = array(
4891 'type' => 'success',
4892 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4893 'msg' => array('template_removed', htmlspecialchars($id))
4894 );
4895 return true;
4896 }
4897 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004898 case 'alias':
4899 if (!is_array($_data['id'])) {
4900 $ids = array();
4901 $ids[] = $_data['id'];
4902 }
4903 else {
4904 $ids = $_data['id'];
4905 }
4906 foreach ($ids as $id) {
4907 $alias_data = mailbox('get', 'alias_details', $id);
4908 if (empty($alias_data)) {
4909 $_SESSION['return'][] = array(
4910 'type' => 'danger',
4911 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4912 'msg' => 'access_denied'
4913 );
4914 continue;
4915 }
4916 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `id` = :id");
4917 $stmt->execute(array(
4918 ':id' => $alias_data['id']
4919 ));
4920 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `send_as` = :alias_address");
4921 $stmt->execute(array(
4922 ':alias_address' => $alias_data['address']
4923 ));
4924 $_SESSION['return'][] = array(
4925 'type' => 'success',
4926 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4927 'msg' => array('alias_removed', htmlspecialchars($alias_data['address']))
4928 );
4929 }
4930 break;
4931 case 'alias_domain':
4932 if (!is_array($_data['alias_domain'])) {
4933 $alias_domains = array();
4934 $alias_domains[] = $_data['alias_domain'];
4935 }
4936 else {
4937 $alias_domains = $_data['alias_domain'];
4938 }
4939 foreach ($alias_domains as $alias_domain) {
4940 if (!is_valid_domain_name($alias_domain)) {
4941 $_SESSION['return'][] = array(
4942 'type' => 'danger',
4943 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4944 'msg' => 'domain_invalid'
4945 );
4946 continue;
4947 }
4948 $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
4949 WHERE `alias_domain`= :alias_domain");
4950 $stmt->execute(array(':alias_domain' => $alias_domain));
4951 $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
4952 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
4953 $_SESSION['return'][] = array(
4954 'type' => 'danger',
4955 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4956 'msg' => 'access_denied'
4957 );
4958 continue;
4959 }
4960 $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
4961 $stmt->execute(array(
4962 ':alias_domain' => $alias_domain,
4963 ));
4964 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :alias_domain");
4965 $stmt->execute(array(
4966 ':alias_domain' => $alias_domain,
4967 ));
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01004968 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
4969 $stmt->execute(array(
4970 ':domain' => '%@'.$alias_domain,
4971 ));
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004972 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
4973 $stmt->execute(array(
4974 ':alias_domain' => $alias_domain,
4975 ));
4976 try {
4977 $redis->hDel('DOMAIN_MAP', $alias_domain);
4978 $redis->hDel('RL_VALUE', $domain);
4979 }
4980 catch (RedisException $e) {
4981 $_SESSION['return'][] = array(
4982 'type' => 'danger',
4983 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4984 'msg' => array('redis_error', $e)
4985 );
4986 continue;
4987 }
4988 $_SESSION['return'][] = array(
4989 'type' => 'success',
4990 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4991 'msg' => array('alias_domain_removed', htmlspecialchars($alias_domain))
4992 );
4993 }
4994 break;
4995 case 'mailbox':
4996 if (!is_array($_data['username'])) {
4997 $usernames = array();
4998 $usernames[] = $_data['username'];
4999 }
5000 else {
5001 $usernames = $_data['username'];
5002 }
5003 foreach ($usernames as $username) {
5004 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
5005 $_SESSION['return'][] = array(
5006 'type' => 'danger',
5007 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5008 'msg' => 'access_denied'
5009 );
5010 continue;
5011 }
5012 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
5013 $_SESSION['return'][] = array(
5014 'type' => 'danger',
5015 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5016 'msg' => 'access_denied'
5017 );
5018 continue;
5019 }
5020 $mailbox_details = mailbox('get', 'mailbox_details', $username);
5021 if (!empty($mailbox_details['domain']) && !empty($mailbox_details['local_part'])) {
5022 $maildir = $mailbox_details['domain'] . '/' . $mailbox_details['local_part'];
5023 $exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $maildir);
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005024
5025 if (getenv("CLUSTERMODE") == "replication") {
5026 // broadcast to each dovecot container
5027 docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
5028 } else {
5029 $maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
5030 if ($maildir_gc['type'] != 'success') {
5031 $_SESSION['return'][] = array(
5032 'type' => 'warning',
5033 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5034 'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
5035 );
5036 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005037 }
5038 }
5039 else {
5040 $_SESSION['return'][] = array(
5041 'type' => 'warning',
5042 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5043 'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty'
5044 );
5045 }
5046 if (strtolower(getenv('SKIP_SOLR')) == 'n') {
5047 $curl = curl_init();
5048 curl_setopt($curl, CURLOPT_URL, 'http://solr:8983/solr/dovecot-fts/update?commit=true');
5049 curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: text/xml'));
5050 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
5051 curl_setopt($curl, CURLOPT_POST, 1);
5052 curl_setopt($curl, CURLOPT_POSTFIELDS, '<delete><query>user:' . $username . '</query></delete>');
5053 curl_setopt($curl, CURLOPT_TIMEOUT, 30);
5054 $response = curl_exec($curl);
5055 if ($response === false) {
5056 $err = curl_error($curl);
5057 $_SESSION['return'][] = array(
5058 'type' => 'warning',
5059 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5060 'msg' => 'Could not remove Solr index: ' . print_r($err, true)
5061 );
5062 }
5063 curl_close($curl);
5064 }
5065 $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
5066 $stmt->execute(array(
5067 ':username' => $username
5068 ));
5069 $stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username");
5070 $stmt->execute(array(
5071 ':username' => $username
5072 ));
5073 $stmt = $pdo->prepare("DELETE FROM `quarantine` WHERE `rcpt` = :username");
5074 $stmt->execute(array(
5075 ':username' => $username
5076 ));
5077 $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :username");
5078 $stmt->execute(array(
5079 ':username' => $username
5080 ));
5081 $stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` = :username");
5082 $stmt->execute(array(
5083 ':username' => $username
5084 ));
5085 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
5086 $stmt->execute(array(
5087 ':username' => $username
5088 ));
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005089 $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as OR `send_as` = :send_as");
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005090 $stmt->execute(array(
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005091 ':logged_in_as' => $username,
5092 ':send_as' => $username
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005093 ));
5094 // fk, better safe than sorry
5095 $stmt = $pdo->prepare("DELETE FROM `user_acl` WHERE `username` = :username");
5096 $stmt->execute(array(
5097 ':username' => $username
5098 ));
5099 $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username");
5100 $stmt->execute(array(
5101 ':username' => $username
5102 ));
5103 $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `user2` = :username");
5104 $stmt->execute(array(
5105 ':username' => $username
5106 ));
5107 $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username");
5108 $stmt->execute(array(
5109 ':username' => $username
5110 ));
5111 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
5112 $stmt->execute(array(
5113 ':username' => $username
5114 ));
5115 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5116 $stmt->execute(array(
5117 ':username' => $username
5118 ));
5119 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
5120 $stmt->execute(array(
5121 ':username' => $username
5122 ));
5123 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5124 $stmt->execute(array(
5125 ':username' => $username
5126 ));
5127 $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)");
5128 $stmt->execute(array(
5129 ':username' => $username
5130 ));
5131 $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)");
5132 $stmt->execute(array(
5133 ':username' => $username
5134 ));
5135 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
5136 $stmt->execute(array(
5137 ':username' => $username
5138 ));
5139 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :username");
5140 $stmt->execute(array(
5141 ':username' => $username
5142 ));
5143 $stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` WHERE `user_id` = :username");
5144 $stmt->execute(array(
5145 ':username' => $username
5146 ));
5147 $stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `user_id` = :username");
5148 $stmt->execute(array(
5149 ':username' => $username
5150 ));
5151 $stmt = $pdo->prepare("DELETE FROM `oauth_authorization_codes` WHERE `user_id` = :username");
5152 $stmt->execute(array(
5153 ':username' => $username
5154 ));
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02005155 $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
5156 $stmt->execute(array(
5157 ':username' => $username,
5158 ));
5159 $stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
5160 $stmt->execute(array(
5161 ':username' => $username,
5162 ));
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005163 $stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
5164 WHERE `goto` REGEXP :username");
5165 $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
5166 $GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
5167 foreach ($GotoData as $gotos) {
5168 $goto_exploded = explode(',', $gotos['goto']);
5169 if (($key = array_search($username, $goto_exploded)) !== false) {
5170 unset($goto_exploded[$key]);
5171 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02005172 $gotos_rebuild = implode(',', (array)$goto_exploded);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005173 $stmt = $pdo->prepare("UPDATE `alias` SET
5174 `goto` = :goto
5175 WHERE `address` = :address");
5176 $stmt->execute(array(
5177 ':goto' => $gotos_rebuild,
5178 ':address' => $gotos['address']
5179 ));
5180 }
5181 try {
5182 $redis->hDel('RL_VALUE', $username);
5183 }
5184 catch (RedisException $e) {
5185 $_SESSION['return'][] = array(
5186 'type' => 'danger',
5187 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5188 'msg' => array('redis_error', $e)
5189 );
5190 continue;
5191 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005192
5193 update_sogo_static_view($username);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005194 $_SESSION['return'][] = array(
5195 'type' => 'success',
5196 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5197 'msg' => array('mailbox_removed', htmlspecialchars($username))
5198 );
5199 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005200 return true;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005201 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01005202 case 'mailbox_templates':
5203 if ($_SESSION['mailcow_cc_role'] != "admin") {
5204 $_SESSION['return'][] = array(
5205 'type' => 'danger',
5206 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5207 'msg' => 'access_denied'
5208 );
5209 return false;
5210 }
5211 if (!is_array($_data['ids'])) {
5212 $ids = array();
5213 $ids[] = $_data['ids'];
5214 }
5215 else {
5216 $ids = $_data['ids'];
5217 }
5218
5219
5220 foreach ($ids as $id) {
5221 // delete template
5222 $stmt = $pdo->prepare("DELETE FROM `templates`
5223 WHERE id = :id AND type = :type AND NOT template = :template");
5224 $stmt->execute(array(
5225 ":id" => $id,
5226 ":type" => "mailbox",
5227 ":template" => "Default"
5228 ));
5229 }
5230
5231 $_SESSION['return'][] = array(
5232 'type' => 'success',
5233 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5234 'msg' => 'template_removed'
5235 );
5236 return true;
5237 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005238 case 'resource':
5239 if (!is_array($_data['name'])) {
5240 $names = array();
5241 $names[] = $_data['name'];
5242 }
5243 else {
5244 $names = $_data['name'];
5245 }
5246 foreach ($names as $name) {
5247 if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
5248 $_SESSION['return'][] = array(
5249 'type' => 'danger',
5250 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5251 'msg' => 'access_denied'
5252 );
5253 continue;
5254 }
5255 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
5256 $_SESSION['return'][] = array(
5257 'type' => 'danger',
5258 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5259 'msg' => 'access_denied'
5260 );
5261 continue;
5262 }
5263 $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
5264 $stmt->execute(array(
5265 ':username' => $name
5266 ));
5267 $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
5268 $stmt->execute(array(
5269 ':username' => $name
5270 ));
5271 $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5272 $stmt->execute(array(
5273 ':username' => $name
5274 ));
5275 $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
5276 $stmt->execute(array(
5277 ':username' => $name
5278 ));
5279 $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5280 $stmt->execute(array(
5281 ':username' => $name
5282 ));
5283 $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)");
5284 $stmt->execute(array(
5285 ':username' => $name
5286 ));
5287 $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)");
5288 $stmt->execute(array(
5289 ':username' => $name
5290 ));
5291 $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
5292 $stmt->execute(array(
5293 ':username' => $name
5294 ));
5295 $_SESSION['return'][] = array(
5296 'type' => 'success',
5297 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5298 'msg' => array('resource_removed', htmlspecialchars($name))
5299 );
5300 }
5301 break;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01005302 case 'tags_domain':
5303 if (!is_array($_data['domain'])) {
5304 $domains = array();
5305 $domains[] = $_data['domain'];
5306 }
5307 else {
5308 $domains = $_data['domain'];
5309 }
5310 $tags = $_data['tags'];
5311 if (!is_array($tags)) $tags = array();
5312
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01005313
5314 $wasModified = false;
5315 foreach ($domains as $domain) {
5316 if (!is_valid_domain_name($domain)) {
5317 $_SESSION['return'][] = array(
5318 'type' => 'danger',
5319 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5320 'msg' => 'domain_invalid'
5321 );
5322 continue;
5323 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005324 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
5325 $_SESSION['return'][] = array(
5326 'type' => 'danger',
5327 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5328 'msg' => 'access_denied'
5329 );
5330 return false;
5331 }
5332
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01005333 foreach($tags as $tag){
5334 // delete tag
5335 $wasModified = true;
5336 $stmt = $pdo->prepare("DELETE FROM `tags_domain` WHERE `domain` = :domain AND `tag_name` = :tag_name");
5337 $stmt->execute(array(
5338 ':domain' => $domain,
5339 ':tag_name' => $tag,
5340 ));
5341 }
5342 }
5343
5344 if (!$wasModified) return false;
5345 $_SESSION['return'][] = array(
5346 'type' => 'success',
5347 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5348 'msg' => array('domain_modified', $domain)
5349 );
5350 break;
5351 case 'tags_mailbox':
5352 if (!is_array($_data['username'])) {
5353 $usernames = array();
5354 $usernames[] = $_data['username'];
5355 }
5356 else {
5357 $usernames = $_data['username'];
5358 }
5359 $tags = $_data['tags'];
5360 if (!is_array($tags)) $tags = array();
5361
5362 $wasModified = false;
5363 foreach ($usernames as $username) {
5364 if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
5365 $_SESSION['return'][] = array(
5366 'type' => 'danger',
5367 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5368 'msg' => 'email invalid'
5369 );
5370 continue;
5371 }
5372
5373 $is_now = mailbox('get', 'mailbox_details', $username);
5374 $domain = $is_now['domain'];
5375 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
5376 $_SESSION['return'][] = array(
5377 'type' => 'danger',
5378 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5379 'msg' => 'access_denied'
5380 );
5381 continue;
5382 }
5383
5384 // delete tags
5385 foreach($tags as $tag){
5386 $wasModified = true;
5387
5388 $stmt = $pdo->prepare("DELETE FROM `tags_mailbox` WHERE `username` = :username AND `tag_name` = :tag_name");
5389 $stmt->execute(array(
5390 ':username' => $username,
5391 ':tag_name' => $tag,
5392 ));
5393 }
5394 }
5395
5396 if (!$wasModified) return false;
5397 $_SESSION['return'][] = array(
5398 'type' => 'success',
5399 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5400 'msg' => array('mailbox_modified', $username)
5401 );
5402 break;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005403 }
5404 break;
5405 }
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +01005406 if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'resource')) && getenv('SKIP_SOGO') != "y") {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01005407 update_sogo_static_view();
5408 }
5409}