public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Trace
data/web/inc/functions.mailbox.inc.php
Trace helps you understand code history line by line. See who changed each line, when it changed, and which commit introduced it.
Author
Date
Commit
Line
Code
1
<?php
2
function mailbox($_action, $_type, $_data = null, $_extra = null) {
3
global $pdo;
4
global $redis;
5
global $lang;
6
global $MAILBOX_DEFAULT_ATTRIBUTES;
7
global $iam_settings;
9
$_data_log = $_data;
10
!isset($_data_log['password']) ?: $_data_log['password'] = '*';
11
!isset($_data_log['password2']) ?: $_data_log['password2'] = '*';
13
// Track mailboxes affected by alias operations for incremental SOGo updates
14
$update_sogo_mailboxes = array();
16
switch ($_action) {
17
case 'add':
18
switch ($_type) {
19
case 'time_limited_alias':
20
if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
21
$_SESSION['return'][] = array(
22
'type' => 'danger',
23
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
24
'msg' => 'access_denied'
25
);
26
return false;
27
}
28
if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
29
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
30
$_SESSION['return'][] = array(
31
'type' => 'danger',
32
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
33
'msg' => 'access_denied'
34
);
35
return false;
36
}
37
else {
38
$username = $_data['username'];
39
}
40
}
41
else {
42
$username = $_SESSION['mailcow_cc_username'];
43
}
44
if (isset($_data["validity"]) && !filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
45
$_SESSION['return'][] = array(
46
'type' => 'danger',
47
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
48
'msg' => 'validity_missing'
49
);
50
return false;
51
}
52
else {
53
// Default to 1 yr
54
$_data["validity"] = 8760;
55
}
56
if (isset($_data["permanent"]) && filter_var($_data["permanent"], FILTER_VALIDATE_BOOL)) {
57
$permanent = 1;
58
}
59
else {
60
$permanent = 0;
61
}
62
$domain = $_data['domain'];
63
$description = $_data['description'];
64
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
65
$valid_alias_domains = user_get_alias_details($username)['alias_domains'];
66
if (!empty($valid_alias_domains)) {
67
$valid_domains = array_merge($valid_domains, $valid_alias_domains);
68
}
69
if (!in_array($domain, $valid_domains)) {
70
$_SESSION['return'][] = array(
71
'type' => 'danger',
72
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
73
'msg' => 'domain_invalid'
74
);
75
return false;
76
}
77
$validity = strtotime("+" . $_data["validity"] . " hour");
78
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`, `permanent`) VALUES
79
(:address, :description, :goto, :validity, :permanent)");
80
$stmt->execute(array(
81
':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
82
':description' => $description,
83
':goto' => $username,
84
':validity' => $validity,
85
':permanent' => $permanent
86
));
87
$_SESSION['return'][] = array(
88
'type' => 'success',
89
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
90
'msg' => array('mailbox_modified', $username)
91
);
92
break;
93
case 'global_filter':
94
if ($_SESSION['mailcow_cc_role'] != "admin") {
95
$_SESSION['return'][] = array(
96
'type' => 'danger',
97
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
98
'msg' => 'access_denied'
99
);
100
return false;
101
}
102
$sieve = new Sieve\SieveParser();
103
$script_data = $_data['script_data'];
104
$script_data = str_replace("\r\n", "\n", $script_data); // windows -> unix
105
$script_data = str_replace("\r", "\n", $script_data); // remaining -> unix
106
$filter_type = $_data['filter_type'];
107
try {
108
$sieve->parse($script_data);
109
}
110
catch (Exception $e) {
111
$_SESSION['return'][] = array(
112
'type' => 'danger',
113
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
114
'msg' => array('sieve_error', $e->getMessage())
115
);
116
return false;
117
}
118
if ($filter_type == 'prefilter') {
119
try {
120
if (file_exists('/global_sieve/before')) {
121
$filter_handle = fopen('/global_sieve/before', 'w');
122
if (!$filter_handle) {
123
throw new Exception($lang['danger']['file_open_error']);
124
}
125
fwrite($filter_handle, $script_data);
126
fclose($filter_handle);
127
}
128
$restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
129
if ($restart_response['type'] == "success") {
130
$_SESSION['return'][] = array(
131
'type' => 'success',
132
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
133
'msg' => 'dovecot_restart_success'
134
);
135
}
136
else {
137
$_SESSION['return'][] = array(
138
'type' => 'warning',
139
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
140
'msg' => 'dovecot_restart_failed'
141
);
142
}
143
}
144
catch (Exception $e) {
145
$_SESSION['return'][] = array(
146
'type' => 'danger',
147
'log' => array(__FUNCTION__, $_action, $_data_log),
148
'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
149
);
150
return false;
151
}
152
}
153
elseif ($filter_type == 'postfilter') {
154
try {
155
if (file_exists('/global_sieve/after')) {
156
$filter_handle = fopen('/global_sieve/after', 'w');
157
if (!$filter_handle) {
158
throw new Exception($lang['danger']['file_open_error']);
159
}
160
fwrite($filter_handle, $script_data);
161
fclose($filter_handle);
162
}
163
$restart_response = json_decode(docker('post', 'dovecot-mailcow', 'restart'), true);
164
if ($restart_response['type'] == "success") {
165
$_SESSION['return'][] = array(
166
'type' => 'success',
167
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
168
'msg' => 'dovecot_restart_success'
169
);
170
}
171
else {
172
$_SESSION['return'][] = array(
173
'type' => 'warning',
174
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
175
'msg' => 'dovecot_restart_failed'
176
);
177
}
178
}
179
catch (Exception $e) {
180
$_SESSION['return'][] = array(
181
'type' => 'danger',
182
'log' => array(__FUNCTION__, $_action, $_data_log),
183
'msg' => array('global_filter_write_error', htmlspecialchars($e->getMessage()))
184
);
185
return false;
186
}
187
}
188
else {
189
$_SESSION['return'][] = array(
190
'type' => 'danger',
191
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
192
'msg' => 'invalid_filter_type'
193
);
194
return false;
195
}
196
$_SESSION['return'][] = array(
197
'type' => 'success',
198
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
199
'msg' => 'global_filter_written'
200
);
201
return true;
202
break;
203
case 'filter':
204
$sieve = new Sieve\SieveParser();
205
if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
206
$_SESSION['return'][] = array(
207
'type' => 'danger',
208
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
209
'msg' => 'access_denied'
210
);
211
return false;
212
}
213
if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
214
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
215
$_SESSION['return'][] = array(
216
'type' => 'danger',
217
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
218
'msg' => 'access_denied'
219
);
220
return false;
221
}
222
else {
223
$username = $_data['username'];
224
}
225
}
226
elseif ($_SESSION['mailcow_cc_role'] == "user") {
227
$username = $_SESSION['mailcow_cc_username'];
228
}
229
else {
230
$_SESSION['return'][] = array(
231
'type' => 'danger',
232
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
233
'msg' => 'no_user_defined'
234
);
235
return false;
236
}
237
$active = intval($_data['active']);
238
$script_data = $_data['script_data'];
239
$script_desc = $_data['script_desc'];
240
$filter_type = $_data['filter_type'];
241
if (empty($script_data)) {
242
$_SESSION['return'][] = array(
243
'type' => 'danger',
244
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
245
'msg' => 'script_empty'
246
);
247
return false;
248
}
249
try {
250
$sieve->parse($script_data);
251
}
252
catch (Exception $e) {
253
$_SESSION['return'][] = array(
254
'type' => 'danger',
255
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
256
'msg' => array('sieve_error', $e->getMessage())
257
);
258
return false;
259
}
260
if (empty($script_data) || empty($script_desc)) {
261
$_SESSION['return'][] = array(
262
'type' => 'danger',
263
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
264
'msg' => 'value_missing'
265
);
266
return false;
267
}
268
if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
269
$_SESSION['return'][] = array(
270
'type' => 'danger',
271
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
272
'msg' => 'filter_type'
273
);
274
return false;
275
}
276
if (!empty($active)) {
277
$script_name = 'active';
278
$stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type");
279
$stmt->execute(array(
280
':username' => $username,
281
':filter_type' => $filter_type
282
));
283
}
284
else {
285
$script_name = 'inactive';
286
}
287
$stmt = $pdo->prepare("INSERT INTO `sieve_filters` (`username`, `script_data`, `script_desc`, `script_name`, `filter_type`)
288
VALUES (:username, :script_data, :script_desc, :script_name, :filter_type)");
289
$stmt->execute(array(
290
':username' => $username,
291
':script_data' => $script_data,
292
':script_desc' => $script_desc,
293
':script_name' => $script_name,
294
':filter_type' => $filter_type
295
));
296
$_SESSION['return'][] = array(
297
'type' => 'success',
298
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
299
'msg' => array('mailbox_modified', $username)
300
);
301
break;
302
case 'syncjob':
303
if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
304
$_SESSION['return'][] = array(
305
'type' => 'danger',
306
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
307
'msg' => 'access_denied'
308
);
309
return false;
310
}
311
if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
312
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
313
$_SESSION['return'][] = array(
314
'type' => 'danger',
315
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
316
'msg' => 'access_denied'
317
);
318
return false;
319
}
320
else {
321
$username = $_data['username'];
322
}
323
}
324
elseif ($_SESSION['mailcow_cc_role'] == "user") {
325
$username = $_SESSION['mailcow_cc_username'];
326
}
327
else {
328
$_SESSION['return'][] = array(
329
'type' => 'danger',
330
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
331
'msg' => 'no_user_defined'
332
);
333
return false;
334
}
335
$active = intval($_data['active']);
336
$subscribeall = intval($_data['subscribeall']);
337
$delete2duplicates = intval($_data['delete2duplicates']);
338
$delete1 = intval($_data['delete1']);
339
$delete2 = intval($_data['delete2']);
340
$timeout1 = intval($_data['timeout1']);
341
$timeout2 = intval($_data['timeout2']);
342
$skipcrossduplicates = intval($_data['skipcrossduplicates']);
343
$automap = intval($_data['automap']);
344
$dry = intval($_data['dry']);
345
$port1 = $_data['port1'];
346
$host1 = strtolower($_data['host1']);
347
$password1 = $_data['password1'];
348
$exclude = $_data['exclude'];
349
$maxage = $_data['maxage'];
350
$maxbytespersecond = $_data['maxbytespersecond'];
351
$subfolder2 = $_data['subfolder2'];
352
$user1 = $_data['user1'];
353
$mins_interval = $_data['mins_interval'];
354
$enc1 = $_data['enc1'];
355
$custom_params = (empty(trim($_data['custom_params']))) ? '' : trim($_data['custom_params']);
357
// validate custom params
358
foreach (explode('-', $custom_params) as $param){
359
if(empty($param)) continue;
361
// extract option
362
if (str_contains($param, '=')) $param = explode('=', $param)[0];
363
else $param = rtrim($param, ' ');
364
// remove first char if first char is -
365
if ($param[0] == '-') $param = ltrim($param, $param[0]);
367
if (str_contains($param, ' ')) {
368
// bad char
369
$_SESSION['return'][] = array(
370
'type' => 'danger',
371
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
372
'msg' => 'bad character SPACE'
373
);
374
return false;
375
}
377
// check if param is whitelisted
378
if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
379
// bad option
380
$_SESSION['return'][] = array(
381
'type' => 'danger',
382
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
383
'msg' => 'bad option '. $param
384
);
385
return false;
386
}
387
}
388
if (empty($subfolder2)) {
389
$subfolder2 = "";
390
}
391
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
392
$maxage = "0";
393
}
394
if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
395
$timeout1 = "600";
396
}
397
if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
398
$timeout2 = "600";
399
}
400
if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
401
$maxbytespersecond = "0";
402
}
403
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
404
$_SESSION['return'][] = array(
405
'type' => 'danger',
406
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
407
'msg' => 'access_denied'
408
);
409
return false;
410
}
411
if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
412
$_SESSION['return'][] = array(
413
'type' => 'danger',
414
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
415
'msg' => 'access_denied'
416
);
417
return false;
418
}
419
// if (!is_valid_domain_name($host1)) {
420
// $_SESSION['return'][] = array(
421
// 'type' => 'danger',
422
// 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
423
// 'msg' => 'access_denied'
424
// );
425
// return false;
426
// }
427
if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
428
$_SESSION['return'][] = array(
429
'type' => 'danger',
430
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
431
'msg' => 'access_denied'
432
);
433
return false;
434
}
435
if (@preg_match("/" . $exclude . "/", null) === false) {
436
$_SESSION['return'][] = array(
437
'type' => 'danger',
438
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
439
'msg' => 'access_denied'
440
);
441
return false;
442
}
443
$stmt = $pdo->prepare("SELECT '1' FROM `imapsync`
444
WHERE `user2` = :user2 AND `user1` = :user1 AND `host1` = :host1");
445
$stmt->execute(array(':user1' => $user1, ':user2' => $username, ':host1' => $host1));
446
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
447
if ($num_results != 0) {
448
$_SESSION['return'][] = array(
449
'type' => 'danger',
450
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
451
'msg' => array('object_exists', htmlspecialchars($host1 . ' / ' . $user1))
452
);
453
return false;
454
}
455
$stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `delete2`, `timeout1`, `timeout2`, `automap`, `skipcrossduplicates`, `maxbytespersecond`, `subscribeall`, `dry`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `custom_params`, `active`)
456
VALUES (:user2, :exclude, :delete1, :delete2, :timeout1, :timeout2, :automap, :skipcrossduplicates, :maxbytespersecond, :subscribeall, :dry, :maxage, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :custom_params, :active)");
457
$stmt->execute(array(
458
':user2' => $username,
459
':custom_params' => $custom_params,
460
':exclude' => $exclude,
461
':maxage' => $maxage,
462
':delete1' => $delete1,
463
':delete2' => $delete2,
464
':timeout1' => $timeout1,
465
':timeout2' => $timeout2,
466
':automap' => $automap,
467
':skipcrossduplicates' => $skipcrossduplicates,
468
':maxbytespersecond' => $maxbytespersecond,
469
':subscribeall' => $subscribeall,
470
':dry' => $dry,
471
':subfolder2' => $subfolder2,
472
':host1' => $host1,
473
':authmech1' => 'PLAIN',
474
':user1' => $user1,
475
':password1' => $password1,
476
':mins_interval' => $mins_interval,
477
':port1' => $port1,
478
':enc1' => $enc1,
479
':delete2duplicates' => $delete2duplicates,
480
':active' => $active,
481
));
482
$_SESSION['return'][] = array(
483
'type' => 'success',
484
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
485
'msg' => array('mailbox_modified', $username)
486
);
487
break;
488
case 'domain':
489
if ($_SESSION['mailcow_cc_role'] != "admin") {
490
$_SESSION['return'][] = array(
491
'type' => 'danger',
492
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
493
'msg' => 'access_denied'
494
);
495
return false;
496
}
497
$DOMAIN_DEFAULT_ATTRIBUTES = null;
498
if ($_data['template']){
499
$DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates', $_data['template'])['attributes'];
500
}
501
if (empty($DOMAIN_DEFAULT_ATTRIBUTES)) {
502
$DOMAIN_DEFAULT_ATTRIBUTES = mailbox('get', 'domain_templates')[0]['attributes'];
503
}
505
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
506
$description = $_data['description'];
507
if (empty($description)) $description = $domain;
508
$tags = (isset($_data['tags'])) ? (array)$_data['tags'] : $DOMAIN_DEFAULT_ATTRIBUTES['tags'];
509
$aliases = (isset($_data['aliases'])) ? (int)$_data['aliases'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_aliases_for_domain'];
510
$mailboxes = (isset($_data['mailboxes'])) ? (int)$_data['mailboxes'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_num_mboxes_for_domain'];
511
$defquota = (isset($_data['defquota'])) ? (int)$_data['defquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['def_quota_for_mbox'] / 1024 ** 2;
512
$maxquota = (isset($_data['maxquota'])) ? (int)$_data['maxquota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_mbox'] / 1024 ** 2;
513
$restart_sogo = (int)$_data['restart_sogo'];
514
$quota = (isset($_data['quota'])) ? (int)$_data['quota'] : $DOMAIN_DEFAULT_ATTRIBUTES['max_quota_for_domain'] / 1024 ** 2;
515
if ($defquota > $maxquota) {
516
$_SESSION['return'][] = array(
517
'type' => 'danger',
518
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
519
'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
520
);
521
return false;
522
}
523
if ($maxquota > $quota) {
524
$_SESSION['return'][] = array(
525
'type' => 'danger',
526
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
527
'msg' => 'mailbox_quota_exceeds_domain_quota'
528
);
529
return false;
530
}
531
if ($defquota == "0" || empty($defquota)) {
532
$_SESSION['return'][] = array(
533
'type' => 'danger',
534
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
535
'msg' => 'defquota_empty'
536
);
537
return false;
538
}
539
if ($maxquota == "0" || empty($maxquota)) {
540
$_SESSION['return'][] = array(
541
'type' => 'danger',
542
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
543
'msg' => 'maxquota_empty'
544
);
545
return false;
546
}
547
$active = (isset($_data['active'])) ? intval($_data['active']) : $DOMAIN_DEFAULT_ATTRIBUTES['active'];
548
$relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_all_recipients'];
549
$relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $DOMAIN_DEFAULT_ATTRIBUTES['relay_unknown_only'];
550
$backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $DOMAIN_DEFAULT_ATTRIBUTES['backupmx'];
551
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $DOMAIN_DEFAULT_ATTRIBUTES['gal'];
552
if ($relay_all_recipients == 1) {
553
$backupmx = '1';
554
}
555
if ($relay_unknown_only == 1) {
556
$backupmx = 1;
557
$relay_all_recipients = 1;
558
}
559
if (!is_valid_domain_name($domain)) {
560
$_SESSION['return'][] = array(
561
'type' => 'danger',
562
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
563
'msg' => 'domain_invalid'
564
);
565
return false;
566
}
567
foreach (array($quota, $maxquota, $mailboxes, $aliases) as $data) {
568
if (!is_numeric($data)) {
569
$_SESSION['return'][] = array(
570
'type' => 'danger',
571
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
572
'msg' => array('object_is_not_numeric', htmlspecialchars($data))
573
);
574
return false;
575
}
576
}
577
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
578
WHERE `domain` = :domain");
579
$stmt->execute(array(':domain' => $domain));
580
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
581
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
582
WHERE `alias_domain` = :domain");
583
$stmt->execute(array(':domain' => $domain));
584
$num_results = $num_results + count($stmt->fetchAll(PDO::FETCH_ASSOC));
585
if ($num_results != 0) {
586
$_SESSION['return'][] = array(
587
'type' => 'danger',
588
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
589
'msg' => array('domain_exists', htmlspecialchars($domain))
590
);
591
return false;
592
}
593
if ($domain == getenv('MAILCOW_HOSTNAME')) {
594
$_SESSION['return'][] = array(
595
'type' => 'danger',
596
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
597
'msg' => 'domain_cannot_match_hostname'
598
);
599
return false;
600
}
602
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
603
$stmt->execute(array(
604
':domain' => '%@' . $domain
605
));
606
// save domain
607
$stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `defquota`, `maxquota`, `quota`, `backupmx`, `gal`, `active`, `relay_unknown_only`, `relay_all_recipients`)
608
VALUES (:domain, :description, :aliases, :mailboxes, :defquota, :maxquota, :quota, :backupmx, :gal, :active, :relay_unknown_only, :relay_all_recipients)");
609
$stmt->execute(array(
610
':domain' => $domain,
611
':description' => $description,
612
':aliases' => $aliases,
613
':mailboxes' => $mailboxes,
614
':defquota' => $defquota,
615
':maxquota' => $maxquota,
616
':quota' => $quota,
617
':backupmx' => $backupmx,
618
':gal' => $gal,
619
':active' => $active,
620
':relay_unknown_only' => $relay_unknown_only,
621
':relay_all_recipients' => $relay_all_recipients
622
));
623
// save tags
624
foreach($tags as $index => $tag){
625
if (empty($tag)) continue;
626
if ($index > $GLOBALS['TAGGING_LIMIT']) {
627
$_SESSION['return'][] = array(
628
'type' => 'warning',
629
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
630
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
631
);
632
break;
633
}
634
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
635
$stmt->execute(array(
636
':domain' => $domain,
637
':tag_name' => $tag,
638
));
639
}
641
try {
642
$redis->hSet('DOMAIN_MAP', $domain, 1);
643
}
644
catch (RedisException $e) {
645
$_SESSION['return'][] = array(
646
'type' => 'danger',
647
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
648
'msg' => array('redis_error', $e)
649
);
650
return false;
651
}
652
$_data['rl_value'] = (isset($_data['rl_value'])) ? intval($_data['rl_value']) : $DOMAIN_DEFAULT_ATTRIBUTES['rl_value'];
653
$_data['rl_frame'] = (isset($_data['rl_frame'])) ? $_data['rl_frame'] : $DOMAIN_DEFAULT_ATTRIBUTES['rl_frame'];
654
if (!empty($_data['rl_value']) && !empty($_data['rl_frame'])){
655
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $domain));
656
}
657
$_data['key_size'] = (isset($_data['key_size'])) ? intval($_data['key_size']) : $DOMAIN_DEFAULT_ATTRIBUTES['key_size'];
658
$_data['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : $DOMAIN_DEFAULT_ATTRIBUTES['dkim_selector'];
659
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
660
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
661
$_SESSION['return'][] = array(
662
'type' => 'success',
663
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
664
'msg' => 'domain_add_dkim_available'
665
);
666
}
667
else {
668
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
669
}
670
}
671
if (!empty($restart_sogo)) {
672
$restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
673
if ($restart_response['type'] == "success") {
674
$_SESSION['return'][] = array(
675
'type' => 'success',
676
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
677
'msg' => array('domain_added', htmlspecialchars($domain))
678
);
679
return true;
680
}
681
else {
682
$_SESSION['return'][] = array(
683
'type' => 'warning',
684
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
685
'msg' => 'domain_added_sogo_failed'
686
);
687
return false;
688
}
689
}
690
$_SESSION['return'][] = array(
691
'type' => 'success',
692
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
693
'msg' => array('domain_added', htmlspecialchars($domain))
694
);
695
return true;
696
break;
697
case 'alias':
698
$addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
699
$gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
700
$internal = intval($_data['internal']);
701
$active = intval($_data['active']);
702
$sender_allowed = intval($_data['sender_allowed']);
703
$sogo_visible = intval($_data['sogo_visible']);
704
$goto_null = intval($_data['goto_null']);
705
$goto_spam = intval($_data['goto_spam']);
706
$goto_ham = intval($_data['goto_ham']);
707
$private_comment = $_data['private_comment'];
708
$public_comment = $_data['public_comment'];
709
if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
710
$_SESSION['return'][] = array(
711
'type' => 'danger',
712
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
713
'msg' => 'comment_too_long'
714
);
715
return false;
716
}
717
if (empty($addresses[0])) {
718
$_SESSION['return'][] = array(
719
'type' => 'danger',
720
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
721
'msg' => 'alias_empty'
722
);
723
return false;
724
}
725
if (empty($gotos[0]) && ($goto_null + $goto_spam + $goto_ham == 0)) {
726
$_SESSION['return'][] = array(
727
'type' => 'danger',
728
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
729
'msg' => 'goto_empty'
730
);
731
return false;
732
}
733
if ($goto_null == "1") {
734
$goto = "null@localhost";
735
}
736
elseif ($goto_spam == "1") {
737
$goto = "spam@localhost";
738
}
739
elseif ($goto_ham == "1") {
740
$goto = "ham@localhost";
741
}
742
else {
743
foreach ($gotos as $i => &$goto) {
744
if (empty($goto)) {
745
continue;
746
}
747
$goto_domain = idn_to_ascii(substr(strstr($goto, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
748
$goto_local_part = strstr($goto, '@', true);
749
$goto = $goto_local_part.'@'.$goto_domain;
750
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
751
WHERE `kind` REGEXP 'location|thing|group'
752
AND `username`= :goto");
753
$stmt->execute(array(':goto' => $goto));
754
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
755
if ($num_results != 0) {
756
$_SESSION['return'][] = array(
757
'type' => 'danger',
758
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
759
'msg' => array('goto_invalid', htmlspecialchars($goto))
760
);
761
unset($gotos[$i]);
762
continue;
763
}
764
if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
765
$_SESSION['return'][] = array(
766
'type' => 'danger',
767
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
768
'msg' => array('goto_invalid', htmlspecialchars($goto))
769
);
770
unset($gotos[$i]);
771
continue;
772
}
773
}
774
$gotos = array_unique($gotos);
775
$gotos = array_filter($gotos);
776
if (empty($gotos)) { return false; }
777
$goto = implode(",", (array)$gotos);
778
}
779
foreach ($addresses as $address) {
780
if (empty($address)) {
781
continue;
782
}
783
if (in_array($address, $gotos)) {
784
continue;
785
}
786
$domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
787
$local_part = strstr($address, '@', true);
788
$address = $local_part.'@'.$domain;
789
$domaindata = mailbox('get', 'domain_details', $domain);
790
if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
791
$_SESSION['return'][] = array(
792
'type' => 'danger',
793
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
794
'msg' => 'max_alias_exceeded'
795
);
796
return false;
797
}
798
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
799
WHERE `address`= :address OR `address` IN (
800
SELECT `username` FROM `mailbox`, `alias_domain`
801
WHERE (
802
`alias_domain`.`alias_domain` = :address_d
803
AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
804
$stmt->execute(array(
805
':address' => $address,
806
':address_l' => $local_part,
807
':address_d' => $domain
808
));
809
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
810
if ($num_results != 0) {
811
$_SESSION['return'][] = array(
812
'type' => 'danger',
813
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
814
'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
815
);
816
continue;
817
}
818
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
819
WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
820
$stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
821
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
822
if ($num_results == 0) {
823
$_SESSION['return'][] = array(
824
'type' => 'danger',
825
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
826
'msg' => array('domain_not_found', htmlspecialchars($domain))
827
);
828
continue;
829
}
830
$stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
831
WHERE `address`= :address");
832
$stmt->execute(array(':address' => $address));
833
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
834
if ($num_results != 0) {
835
$_SESSION['return'][] = array(
836
'type' => 'danger',
837
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
838
'msg' => array('is_spam_alias', htmlspecialchars($address))
839
);
840
continue;
841
}
842
if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
843
$_SESSION['return'][] = array(
844
'type' => 'danger',
845
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
846
'msg' => array('alias_invalid', $address)
847
);
848
continue;
849
}
850
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
851
$_SESSION['return'][] = array(
852
'type' => 'danger',
853
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
854
'msg' => 'access_denied'
855
);
856
continue;
857
}
858
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `internal`, `sender_allowed`, `active`)
859
VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :internal, :sender_allowed, :active)");
860
if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
861
$stmt->execute(array(
862
':address' => '@'.$domain,
863
':public_comment' => $public_comment,
864
':private_comment' => $private_comment,
865
':address' => '@'.$domain,
866
':goto' => $goto,
867
':domain' => $domain,
868
':sogo_visible' => $sogo_visible,
869
':internal' => $internal,
870
':sender_allowed' => $sender_allowed,
871
':active' => $active
872
));
873
}
874
else {
875
$stmt->execute(array(
876
':address' => $address,
877
':public_comment' => $public_comment,
878
':private_comment' => $private_comment,
879
':goto' => $goto,
880
':domain' => $domain,
881
':sogo_visible' => $sogo_visible,
882
':internal' => $internal,
883
':sender_allowed' => $sender_allowed,
884
':active' => $active
885
));
886
}
887
$id = $pdo->lastInsertId();
888
$_SESSION['return'][] = array(
889
'type' => 'success',
890
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
891
'msg' => array('alias_added', $address, $id)
892
);
894
// Track affected mailboxes for SOGo update
895
if (!empty($goto)) {
896
$gotos = array_map('trim', explode(',', $goto));
897
foreach ($gotos as $g) {
898
if (filter_var($g, FILTER_VALIDATE_EMAIL) &&
899
!in_array($g, array('null@localhost', 'spam@localhost', 'ham@localhost'))) {
900
$update_sogo_mailboxes[] = $g;
901
}
902
}
903
}
904
}
905
break;
906
case 'alias_domain':
907
$active = intval($_data['active']);
908
$alias_domains = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['alias_domain']));
909
$alias_domains = array_filter($alias_domains);
910
$target_domain = idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46);
911
if (!isset($_SESSION['acl']['alias_domains']) || $_SESSION['acl']['alias_domains'] != "1" ) {
912
$_SESSION['return'][] = array(
913
'type' => 'danger',
914
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
915
'msg' => 'access_denied'
916
);
917
return false;
918
}
919
if (!is_valid_domain_name($target_domain)) {
920
$_SESSION['return'][] = array(
921
'type' => 'danger',
922
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
923
'msg' => 'target_domain_invalid'
924
);
925
return false;
926
}
927
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
928
$_SESSION['return'][] = array(
929
'type' => 'danger',
930
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
931
'msg' => 'access_denied'
932
);
933
return false;
934
}
935
foreach ($alias_domains as $i => $alias_domain) {
936
$alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
937
if (!is_valid_domain_name($alias_domain)) {
938
$_SESSION['return'][] = array(
939
'type' => 'danger',
940
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
941
'msg' => array('alias_domain_invalid', htmlspecialchars(alias_domain))
942
);
943
continue;
944
}
945
if ($alias_domain == $target_domain) {
946
$_SESSION['return'][] = array(
947
'type' => 'danger',
948
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
949
'msg' => array('aliasd_targetd_identical', htmlspecialchars($target_domain))
950
);
951
continue;
952
}
953
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
954
WHERE `domain`= :target_domain");
955
$stmt->execute(array(':target_domain' => $target_domain));
956
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
957
if ($num_results == 0) {
958
$_SESSION['return'][] = array(
959
'type' => 'danger',
960
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
961
'msg' => array('targetd_not_found', htmlspecialchars($target_domain))
962
);
963
continue;
964
}
965
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
966
WHERE `domain`= :target_domain AND `backupmx` = '1'");
967
$stmt->execute(array(':target_domain' => $target_domain));
968
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
969
if ($num_results == 1) {
970
$_SESSION['return'][] = array(
971
'type' => 'danger',
972
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
973
'msg' => array('targetd_relay_domain', htmlspecialchars($target_domain))
974
);
975
continue;
976
}
977
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain
978
UNION
979
SELECT `domain` FROM `domain` WHERE `domain`= :alias_domain_in_domain");
980
$stmt->execute(array(':alias_domain' => $alias_domain, ':alias_domain_in_domain' => $alias_domain));
981
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
982
if ($num_results != 0) {
983
$_SESSION['return'][] = array(
984
'type' => 'danger',
985
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
986
'msg' => array('alias_domain_invalid', $alias_domain)
987
);
988
continue;
989
}
990
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `send_as` LIKE :domain");
991
$stmt->execute(array(
992
':domain' => '%@' . $domain
993
));
994
$stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
995
VALUES (:alias_domain, :target_domain, :active)");
996
$stmt->execute(array(
997
':alias_domain' => $alias_domain,
998
':target_domain' => $target_domain,
999
':active' => $active
1000
));
1001
try {
1002
$redis->hSet('DOMAIN_MAP', $alias_domain, 1);
1003
}
1004
catch (RedisException $e) {
1005
$_SESSION['return'][] = array(
1006
'type' => 'danger',
1007
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1008
'msg' => array('redis_error', $e)
1009
);
1010
return false;
1011
}
1012
if (!empty(intval($_data['rl_value']))) {
1013
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
1014
}
1015
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
1016
if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
1017
$_SESSION['return'][] = array(
1018
'type' => 'success',
1019
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1020
'msg' => 'domain_add_dkim_available'
1021
);
1022
}
1023
else {
1024
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $alias_domain));
1025
}
1026
}
1027
$_SESSION['return'][] = array(
1028
'type' => 'success',
1029
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1030
'msg' => array('aliasd_added', htmlspecialchars($alias_domain))
1031
);
1032
}
1033
break;
1034
case 'mailbox':
1035
$local_part = strtolower(trim($_data['local_part']));
1036
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1037
$username = $local_part . '@' . $domain;
1038
$authsource = 'mailcow';
1039
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
1040
$_SESSION['return'][] = array(
1041
'type' => 'danger',
1042
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1043
'msg' => 'mailbox_invalid'
1044
);
1045
return false;
1046
}
1047
if (empty($_data['local_part'])) {
1048
$_SESSION['return'][] = array(
1049
'type' => 'danger',
1050
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1051
'msg' => 'mailbox_invalid'
1052
);
1053
return false;
1054
}
1055
if ($_data['authsource'] == "mailcow" ||
1056
in_array($_data['authsource'], array('keycloak', 'generic-oidc', 'ldap')) && $iam_settings['authsource'] == $_data['authsource']){
1057
$authsource = $_data['authsource'];
1058
}
1059
if (empty($name)) {
1060
$name = $local_part;
1061
}
1062
$template_attr = null;
1063
if ($_data['template']){
1064
$template_attr = mailbox('get', 'mailbox_templates', $_data['template'], $_extra)['attributes'];
1065
}
1066
if (empty($template_attr)) {
1067
$template_attr = mailbox('get', 'mailbox_templates', null, $_extra)[0]['attributes'];
1068
}
1069
$MAILBOX_DEFAULT_ATTRIBUTES = array_merge($MAILBOX_DEFAULT_ATTRIBUTES, $template_attr);
1071
$password = $_data['password'];
1072
$password2 = $_data['password2'];
1073
$name = ltrim(rtrim($_data['name'], '>'), '<');
1074
$tags = (isset($_data['tags'])) ? $_data['tags'] : $MAILBOX_DEFAULT_ATTRIBUTES['tags'];
1075
$quota_m = (isset($_data['quota'])) ? intval($_data['quota']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['quota']) / 1024 ** 2;
1076
if ($authsource != 'mailcow'){
1077
$password = '';
1078
$password2 = '';
1079
$password_hashed = '';
1080
}
1081
if (!hasACLAccess("unlimited_quota") && $quota_m === 0) {
1082
$_SESSION['return'][] = array(
1083
'type' => 'danger',
1084
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1085
'msg' => 'unlimited_quota_acl'
1086
);
1087
return false;
1088
}
1090
if (isset($_data['protocol_access'])) {
1091
$_data['protocol_access'] = (array)$_data['protocol_access'];
1092
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
1093
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
1094
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
1095
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
1096
$_data['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
1097
$_data['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
1098
}
1099
$active = (isset($_data['active'])) ? intval($_data['active']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['active']);
1100
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1101
$force_tfa = (isset($_data['force_tfa'])) ? intval($_data['force_tfa']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_tfa']);
1102
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1103
$tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1104
$sogo_access = (isset($_data['sogo_access'])) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1105
$imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1106
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1107
$smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
1108
$sieve_access = (isset($_data['sieve_access'])) ? intval($_data['sieve_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
1109
$eas_access = (isset($_data['eas_access'])) ? intval($_data['eas_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['eas_access']);
1110
$dav_access = (isset($_data['dav_access'])) ? intval($_data['dav_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['dav_access']);
1111
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
1112
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1113
$quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
1114
// Validate quarantine_category
1115
if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
1116
$_SESSION['return'][] = array(
1117
'type' => 'danger',
1118
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1119
'msg' => 'quarantine_category_invalid'
1120
);
1121
return false;
1122
}
1123
$quota_b = ($quota_m * 1048576);
1124
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
1125
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
1126
$force_pw_update = 0;
1127
}
1128
if ($authsource == 'generic-oidc'){
1129
$force_tfa = 0;
1130
}
1131
$mailbox_attrs = json_encode(
1132
array(
1133
'force_pw_update' => strval($force_pw_update),
1134
'force_tfa' => strval($force_tfa),
1135
'tls_enforce_in' => strval($tls_enforce_in),
1136
'tls_enforce_out' => strval($tls_enforce_out),
1137
'sogo_access' => strval($sogo_access),
1138
'imap_access' => strval($imap_access),
1139
'pop3_access' => strval($pop3_access),
1140
'smtp_access' => strval($smtp_access),
1141
'sieve_access' => strval($sieve_access),
1142
'eas_access' => strval($eas_access),
1143
'dav_access' => strval($dav_access),
1144
'relayhost' => strval($relayhost),
1145
'passwd_update' => time(),
1146
'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
1147
'quarantine_notification' => strval($quarantine_notification),
1148
'quarantine_category' => strval($quarantine_category),
1149
'attribute_hash' => $attribute_hash
1150
)
1151
);
1152
if (!is_valid_domain_name($domain)) {
1153
$_SESSION['return'][] = array(
1154
'type' => 'danger',
1155
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1156
'msg' => 'domain_invalid'
1157
);
1158
return false;
1159
}
1160
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1161
$_SESSION['return'][] = array(
1162
'type' => 'danger',
1163
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1164
'msg' => 'access_denied'
1165
);
1166
return false;
1167
}
1168
$stmt = $pdo->prepare("SELECT `mailboxes`, `maxquota`, `quota` FROM `domain`
1169
WHERE `domain` = :domain");
1170
$stmt->execute(array(':domain' => $domain));
1171
$DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
1172
$stmt = $pdo->prepare("SELECT
1173
COUNT(*) as count,
1174
COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
1175
FROM `mailbox`
1176
WHERE (`kind` = '' OR `kind` = NULL)
1177
AND `domain` = :domain");
1178
$stmt->execute(array(':domain' => $domain));
1179
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
1180
$stmt = $pdo->prepare("SELECT `local_part` FROM `mailbox` WHERE `local_part` = :local_part and `domain`= :domain");
1181
$stmt->execute(array(':local_part' => $local_part, ':domain' => $domain));
1182
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1183
if ($num_results != 0) {
1184
$_SESSION['return'][] = array(
1185
'type' => 'danger',
1186
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1187
'msg' => array('object_exists', htmlspecialchars($username))
1188
);
1189
return false;
1190
}
1191
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
1192
$stmt->execute(array(':username' => $username));
1193
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1194
if ($num_results != 0) {
1195
$_SESSION['return'][] = array(
1196
'type' => 'danger',
1197
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1198
'msg' => array('is_alias', htmlspecialchars($username))
1199
);
1200
return false;
1201
}
1202
$stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :username");
1203
$stmt->execute(array(':username' => $username));
1204
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1205
if ($num_results != 0) {
1206
$_SESSION['return'][] = array(
1207
'type' => 'danger',
1208
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1209
'msg' => array('is_spam_alias', htmlspecialchars($username))
1210
);
1211
return false;
1212
}
1213
$stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1214
$stmt->execute(array(':domain' => $domain));
1215
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1216
if ($num_results == 0) {
1217
$_SESSION['return'][] = array(
1218
'type' => 'danger',
1219
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1220
'msg' => array('domain_not_found', htmlspecialchars($domain))
1221
);
1222
return false;
1223
}
1224
if ($authsource == 'mailcow'){
1225
if (password_check($password, $password2) !== true) {
1226
return false;
1227
}
1228
$password_hashed = hash_password($password);
1229
}
1230
if ($MailboxData['count'] >= $DomainData['mailboxes']) {
1231
$_SESSION['return'][] = array(
1232
'type' => 'danger',
1233
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1234
'msg' => array('max_mailbox_exceeded', $MailboxData['count'], $DomainData['mailboxes'])
1235
);
1236
return false;
1237
}
1238
if ($quota_m > $DomainData['maxquota']) {
1239
$_SESSION['return'][] = array(
1240
'type' => 'danger',
1241
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1242
'msg' => array('mailbox_quota_exceeded', $DomainData['maxquota'])
1243
);
1244
return false;
1245
}
1246
if (($MailboxData['quota'] + $quota_m) > $DomainData['quota']) {
1247
$quota_left_m = ($DomainData['quota'] - $MailboxData['quota']);
1248
$_SESSION['return'][] = array(
1249
'type' => 'danger',
1250
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1251
'msg' => array('mailbox_quota_left_exceeded', $quota_left_m)
1252
);
1253
return false;
1254
}
1255
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `attributes`, `authsource`, `active`)
1256
VALUES (:username, :password_hashed, :name, :quota_b, :local_part, :domain, :mailbox_attrs, :authsource, :active)");
1257
$stmt->execute(array(
1258
':username' => $username,
1259
':password_hashed' => $password_hashed,
1260
':name' => $name,
1261
':quota_b' => $quota_b,
1262
':local_part' => $local_part,
1263
':domain' => $domain,
1264
':mailbox_attrs' => $mailbox_attrs,
1265
':authsource' => $authsource,
1266
':active' => $active
1267
));
1268
$stmt = $pdo->prepare("UPDATE `mailbox` SET
1269
`attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
1270
WHERE `username` = :username");
1271
$stmt->execute(array(
1272
':username' => $username
1273
));
1274
// save delimiter_action
1275
if (isset($_data['tagged_mail_handler'])) {
1276
mailbox('edit', 'delimiter_action', array(
1277
'username' => $username,
1278
'tagged_mail_handler' => $_data['tagged_mail_handler']
1279
));
1280
}
1282
// save tags
1283
foreach($tags as $index => $tag){
1284
if (empty($tag)) continue;
1285
if ($index > $GLOBALS['TAGGING_LIMIT']) {
1286
$_SESSION['return'][] = array(
1287
'type' => 'warning',
1288
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1289
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
1290
);
1291
break;
1292
}
1293
try {
1294
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
1295
$stmt->execute(array(
1296
':username' => $username,
1297
':tag_name' => $tag,
1298
));
1299
} catch (Exception $e) {
1300
}
1301
}
1302
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
1303
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1304
$stmt->execute(array(':username' => $username));
1305
$stmt = $pdo->prepare("INSERT INTO `quota2replica` (`username`, `bytes`, `messages`)
1306
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
1307
$stmt->execute(array(':username' => $username));
1308
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
1309
VALUES (:username1, :username2, :domain, :active)");
1310
$stmt->execute(array(
1311
':username1' => $username,
1312
':username2' => $username,
1313
':domain' => $domain,
1314
':active' => $active
1315
));
1318
if (isset($_data['acl'])) {
1319
$_data['acl'] = (array)$_data['acl'];
1320
$_data['spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1321
$_data['tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1322
$_data['spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1323
$_data['spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1324
$_data['delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1325
$_data['syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1326
$_data['eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1327
$_data['sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1328
$_data['pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1329
$_data['quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1330
$_data['quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1331
$_data['quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1332
$_data['quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1333
$_data['app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
1334
$_data['pw_reset'] = (in_array('pw_reset', $_data['acl'])) ? 1 : 0;
1335
} else {
1336
$_data['spam_alias'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_alias']);
1337
$_data['tls_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_tls_policy']);
1338
$_data['spam_score'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_score']);
1339
$_data['spam_policy'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_spam_policy']);
1340
$_data['delimiter_action'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_delimiter_action']);
1341
$_data['syncjobs'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_syncjobs']);
1342
$_data['eas_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_eas_reset']);
1343
$_data['sogo_profile_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_sogo_profile_reset']);
1344
$_data['pushover'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pushover']);
1345
$_data['quarantine'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine']);
1346
$_data['quarantine_attachments'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_attachments']);
1347
$_data['quarantine_notification'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_notification']);
1348
$_data['quarantine_category'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_quarantine_category']);
1349
$_data['app_passwds'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_app_passwds']);
1350
$_data['pw_reset'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['acl_pw_reset']);
1351
}
1353
try {
1354
$stmt = $pdo->prepare("INSERT INTO `user_acl`
1355
(`username`, `spam_alias`, `tls_policy`, `spam_score`, `spam_policy`, `delimiter_action`, `syncjobs`, `eas_reset`, `sogo_profile_reset`,
1356
`pushover`, `quarantine`, `quarantine_attachments`, `quarantine_notification`, `quarantine_category`, `app_passwds`, `pw_reset`)
1357
VALUES (:username, :spam_alias, :tls_policy, :spam_score, :spam_policy, :delimiter_action, :syncjobs, :eas_reset, :sogo_profile_reset,
1358
:pushover, :quarantine, :quarantine_attachments, :quarantine_notification, :quarantine_category, :app_passwds, :pw_reset) ");
1359
$stmt->execute(array(
1360
':username' => $username,
1361
':spam_alias' => $_data['spam_alias'],
1362
':tls_policy' => $_data['tls_policy'],
1363
':spam_score' => $_data['spam_score'],
1364
':spam_policy' => $_data['spam_policy'],
1365
':delimiter_action' => $_data['delimiter_action'],
1366
':syncjobs' => $_data['syncjobs'],
1367
':eas_reset' => $_data['eas_reset'],
1368
':sogo_profile_reset' => $_data['sogo_profile_reset'],
1369
':pushover' => $_data['pushover'],
1370
':quarantine' => $_data['quarantine'],
1371
':quarantine_attachments' => $_data['quarantine_attachments'],
1372
':quarantine_notification' => $_data['quarantine_notification'],
1373
':quarantine_category' => $_data['quarantine_category'],
1374
':app_passwds' => $_data['app_passwds'],
1375
':pw_reset' => $_data['pw_reset']
1376
));
1377
}
1378
catch (PDOException $e) {
1379
$_SESSION['return'][] = array(
1380
'type' => 'danger',
1381
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1382
'msg' => $e->getMessage()
1383
);
1384
return false;
1385
}
1387
$_data['rl_frame'] = (isset($_data['rl_frame'])) ? $_data['rl_frame'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_frame'];
1388
$_data['rl_value'] = (isset($_data['rl_value'])) ? $_data['rl_value'] : $MAILBOX_DEFAULT_ATTRIBUTES['rl_value'];
1389
if (isset($_data['rl_frame']) && isset($_data['rl_value'])){
1390
ratelimit('edit', 'mailbox', array(
1391
'object' => $username,
1392
'rl_frame' => $_data['rl_frame'],
1393
'rl_value' => $_data['rl_value']
1394
), $_extra);
1395
}
1397
// Track affected mailboxes for SOGo update
1398
$update_sogo_mailboxes[] = $username;
1399
$_SESSION['return'][] = array(
1400
'type' => 'success',
1401
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1402
'msg' => array('mailbox_added', htmlspecialchars($username))
1403
);
1404
break;
1405
case 'mailbox_from_template':
1406
$stmt = $pdo->prepare("SELECT * FROM `templates`
1407
WHERE `template` = :template AND type = 'mailbox'");
1408
$stmt->execute(array(
1409
":template" => $_data['template']
1410
));
1411
$mbox_template_data = $stmt->fetch(PDO::FETCH_ASSOC);
1412
if (empty($mbox_template_data)){
1413
$_SESSION['return'][] = array(
1414
'type' => 'danger',
1415
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1416
'msg' => 'template_missing'
1417
);
1418
return false;
1419
}
1421
$attribute_hash = sha1(json_encode($mbox_template_data["attributes"]));
1422
$mbox_template_data = json_decode($mbox_template_data["attributes"], true);
1423
$mbox_template_data['domain'] = $_data['domain'];
1424
$mbox_template_data['name'] = $_data['name'];
1425
$mbox_template_data['local_part'] = $_data['local_part'];
1426
$mbox_template_data['authsource'] = $_data['authsource'];
1427
$mbox_template_data['attribute_hash'] = $attribute_hash;
1428
$mbox_template_data['quota'] = intval($mbox_template_data['quota'] / 1048576);
1430
$mailbox_attributes = array('acl' => array());
1431
foreach ($mbox_template_data as $key => $value){
1432
switch (true) {
1433
case (strpos($key, 'acl_') === 0 && $value != 0):
1434
array_push($mailbox_attributes['acl'], str_replace('acl_' , '', $key));
1435
break;
1436
default:
1437
$mailbox_attributes[$key] = $value;
1438
break;
1439
}
1440
}
1442
return mailbox('add', 'mailbox', $mailbox_attributes);
1443
break;
1444
case 'mta_sts':
1445
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1446
$version = strtolower($_data['version']);
1447
$mode = strtolower($_data['mode']);
1448
$mx = explode(",", preg_replace('/\s+/', '', $_data['mx']));
1449
$max_age = intval($_data['max_age']);
1450
$active = (intval($_data['active']) == 1) ? 1 : 0;
1451
$id = date('YmdHis');
1453
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1454
$_SESSION['return'][] = array(
1455
'type' => 'danger',
1456
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
1457
'msg' => 'access_denied'
1458
);
1459
return false;
1460
}
1461
if (empty($version) || !in_array($version, array('stsv1'))) {
1462
$_SESSION['return'][] = array(
1463
'type' => 'danger',
1464
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
1465
'msg' => array('version_invalid', htmlspecialchars($domain))
1466
);
1467
return false;
1468
}
1469
if (empty($mode) || !in_array($mode, array('enforce', 'testing', 'none'))) {
1470
$_SESSION['return'][] = array(
1471
'type' => 'danger',
1472
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
1473
'msg' => array('mode_invalid', htmlspecialchars($domain))
1474
);
1475
return false;
1476
}
1477
if (empty($max_age) || $max_age < 0 || $max_age > 31536000) {
1478
$_SESSION['return'][] = array(
1479
'type' => 'danger',
1480
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
1481
'msg' => array('max_age_invalid', htmlspecialchars($domain))
1482
);
1483
return false;
1484
}
1485
foreach ($mx as $index => $mx_domain) {
1486
$mx_domain = idn_to_ascii(strtolower(trim($mx_domain)), 0, INTL_IDNA_VARIANT_UTS46);
1487
if (!is_valid_domain_name($mx_domain, array('allow_wildcard' => true))) {
1488
$_SESSION['return'][] = array(
1489
'type' => 'danger',
1490
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
1491
'msg' => array('mx_invalid', htmlspecialchars($mx_domain))
1492
);
1493
return false;
1494
}
1495
}
1497
try {
1498
$stmt = $pdo->prepare("INSERT INTO `mta_sts` (`id`, `domain`, `version`, `mode`, `mx`, `max_age`, `active`)
1499
VALUES (:id, :domain, :version, :mode, :mx, :max_age, :active)");
1500
$stmt->execute(array(
1501
':id' => $id,
1502
':domain' => $domain,
1503
':version' => $version,
1504
':mode' => $mode,
1505
':mx' => implode(",", $mx),
1506
':max_age' => $max_age,
1507
':active' => $active
1508
));
1509
} catch (PDOException $e) {
1510
$_SESSION['return'][] = array(
1511
'type' => 'danger',
1512
'log' => array(__FUNCTION__, $_action, $_type, $_data),
1513
'msg' => $e->getMessage()
1514
);
1515
return false;
1516
}
1517
break;
1518
case 'resource':
1519
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
1520
$description = $_data['description'];
1521
$local_part = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
1522
$name = $local_part . '@' . $domain;
1523
$kind = $_data['kind'];
1524
$multiple_bookings = intval($_data['multiple_bookings']);
1525
$active = intval($_data['active']);
1526
if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
1527
$_SESSION['return'][] = array(
1528
'type' => 'danger',
1529
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1530
'msg' => 'resource_invalid'
1531
);
1532
return false;
1533
}
1534
if (empty($description)) {
1535
$_SESSION['return'][] = array(
1536
'type' => 'danger',
1537
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1538
'msg' => 'description_invalid'
1539
);
1540
return false;
1541
}
1542
if (!isset($multiple_bookings) || $multiple_bookings < -1) {
1543
$multiple_bookings = -1;
1544
}
1545
if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
1546
$_SESSION['return'][] = array(
1547
'type' => 'danger',
1548
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1549
'msg' => 'resource_invalid'
1550
);
1551
return false;
1552
}
1553
if (!is_valid_domain_name($domain)) {
1554
$_SESSION['return'][] = array(
1555
'type' => 'danger',
1556
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1557
'msg' => 'domain_invalid'
1558
);
1559
return false;
1560
}
1561
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
1562
$_SESSION['return'][] = array(
1563
'type' => 'danger',
1564
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1565
'msg' => 'access_denied'
1566
);
1567
return false;
1568
}
1569
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
1570
$stmt->execute(array(':name' => $name));
1571
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1572
if ($num_results != 0) {
1573
$_SESSION['return'][] = array(
1574
'type' => 'danger',
1575
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1576
'msg' => array('object_exists', htmlspecialchars($name))
1577
);
1578
return false;
1579
}
1580
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
1581
$stmt->execute(array(':name' => $name));
1582
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1583
if ($num_results != 0) {
1584
$_SESSION['return'][] = array(
1585
'type' => 'danger',
1586
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1587
'msg' => array('is_alias', htmlspecialchars($name))
1588
);
1589
return false;
1590
}
1591
$stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
1592
$stmt->execute(array(':name' => $name));
1593
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1594
if ($num_results != 0) {
1595
$_SESSION['return'][] = array(
1596
'type' => 'danger',
1597
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1598
'msg' => array('is_spam_alias', htmlspecialchars($name))
1599
);
1600
return false;
1601
}
1602
$stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
1603
$stmt->execute(array(':domain' => $domain));
1604
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
1605
if ($num_results == 0) {
1606
$_SESSION['return'][] = array(
1607
'type' => 'danger',
1608
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1609
'msg' => array('domain_not_found', htmlspecialchars($domain))
1610
);
1611
return false;
1612
}
1613
$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`)
1614
VALUES (:name, 'RESOURCE', :description, 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
1615
$stmt->execute(array(
1616
':name' => $name,
1617
':description' => $description,
1618
':local_part' => $local_part,
1619
':domain' => $domain,
1620
':active' => $active,
1621
':kind' => $kind,
1622
':multiple_bookings' => $multiple_bookings
1623
));
1624
$_SESSION['return'][] = array(
1625
'type' => 'success',
1626
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1627
'msg' => array('resource_added', htmlspecialchars($name))
1628
);
1630
// Track affected mailboxes for SOGo update
1631
$update_sogo_mailboxes[] = $name;
1632
break;
1633
case 'domain_templates':
1634
if ($_SESSION['mailcow_cc_role'] != "admin") {
1635
$_SESSION['return'][] = array(
1636
'type' => 'danger',
1637
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1638
'msg' => 'access_denied'
1639
);
1640
return false;
1641
}
1642
if (empty($_data["template"])){
1643
$_SESSION['return'][] = array(
1644
'type' => 'danger',
1645
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1646
'msg' => 'template_name_invalid'
1647
);
1648
return false;
1649
}
1651
// check if template name exists, return false
1652
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1653
$stmt->execute(array(
1654
":type" => "domain",
1655
":template" => $_data["template"]
1656
));
1657
$row = $stmt->fetch(PDO::FETCH_ASSOC);
1659
if (!empty($row)){
1660
$_SESSION['return'][] = array(
1661
'type' => 'danger',
1662
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1663
'msg' => array('template_exists', $_data["template"])
1664
);
1665
return false;
1666
}
1668
// check attributes
1669
$attr = array();
1670
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1671
$attr['max_num_aliases_for_domain'] = (!empty($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 400;
1672
$attr['max_num_mboxes_for_domain'] = (!empty($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 10;
1673
$attr['def_quota_for_mbox'] = (!empty($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 3072 * 1048576;
1674
$attr['max_quota_for_mbox'] = (!empty($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 10240 * 1048576;
1675
$attr['max_quota_for_domain'] = (!empty($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 10240 * 1048576;
1676
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1677
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1678
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
1679
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
1680
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
1681
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
1682
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
1683
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
1684
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
1686
// save template
1687
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1688
VALUES (:type, :template, :attributes)");
1689
$stmt->execute(array(
1690
":type" => "domain",
1691
":template" => $_data["template"],
1692
":attributes" => json_encode($attr)
1693
));
1695
// success
1696
$_SESSION['return'][] = array(
1697
'type' => 'success',
1698
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1699
'msg' => array('template_added', $_data["template"])
1700
);
1701
return true;
1702
break;
1703
case 'mailbox_templates':
1704
if ($_SESSION['mailcow_cc_role'] != "admin") {
1705
$_SESSION['return'][] = array(
1706
'type' => 'danger',
1707
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1708
'msg' => 'access_denied'
1709
);
1710
return false;
1711
}
1712
if (empty($_data["template"])){
1713
$_SESSION['return'][] = array(
1714
'type' => 'danger',
1715
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1716
'msg' => 'template_name_invalid'
1717
);
1718
return false;
1719
}
1721
// check if template name exists, return false
1722
$stmt = $pdo->prepare("SELECT id FROM `templates` WHERE `type` = :type AND `template` = :template");
1723
$stmt->execute(array(
1724
":type" => "mailbox",
1725
":template" => $_data["template"]
1726
));
1727
$row = $stmt->fetch(PDO::FETCH_ASSOC);
1728
if (!empty($row)){
1729
$_SESSION['return'][] = array(
1730
'type' => 'danger',
1731
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1732
'msg' => array('template_exists', $_data["template"])
1733
);
1734
return false;
1735
}
1738
// check attributes
1739
$attr = array();
1740
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
1741
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
1742
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['tagged_mail_handler']);
1743
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
1744
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
1745
// Validate quarantine_category
1746
if (!in_array($attr["quarantine_category"], array('add_header', 'reject', 'all'))) {
1747
$_SESSION['return'][] = array(
1748
'type' => 'danger',
1749
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
1750
'msg' => 'quarantine_category_invalid'
1751
);
1752
return false;
1753
}
1754
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
1755
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
1756
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
1757
$attr["force_tfa"] = isset($_data['force_tfa']) ? intval($_data['force_tfa']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_tfa']);
1758
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sogo_access']);
1759
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : 1;
1760
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_in']);
1761
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['tls_enforce_out']);
1762
if (isset($_data['protocol_access'])) {
1763
$_data['protocol_access'] = (array)$_data['protocol_access'];
1764
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
1765
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
1766
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
1767
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
1768
$attr['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
1769
$attr['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
1770
}
1771
else {
1772
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
1773
$attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
1774
$attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
1775
$attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
1776
$attr['eas_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['eas_access']);
1777
$attr['dav_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['dav_access']);
1778
}
1779
if (isset($_data['acl'])) {
1780
$_data['acl'] = (array)$_data['acl'];
1781
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
1782
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
1783
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
1784
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
1785
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
1786
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
1787
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
1788
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
1789
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
1790
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
1791
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
1792
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
1793
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
1794
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
1795
$attr['acl_pw_reset'] = (in_array('pw_reset', $_data['acl'])) ? 1 : 0;
1796
} else {
1797
$_data['acl'] = (array)$_data['acl'];
1798
$attr['acl_spam_alias'] = 0;
1799
$attr['acl_tls_policy'] = 0;
1800
$attr['acl_spam_score'] = 0;
1801
$attr['acl_spam_policy'] = 0;
1802
$attr['acl_delimiter_action'] = 0;
1803
$attr['acl_syncjobs'] = 0;
1804
$attr['acl_eas_reset'] = 0;
1805
$attr['acl_sogo_profile_reset'] = 0;
1806
$attr['acl_pushover'] = 0;
1807
$attr['acl_quarantine'] = 0;
1808
$attr['acl_quarantine_attachments'] = 0;
1809
$attr['acl_quarantine_notification'] = 0;
1810
$attr['acl_quarantine_category'] = 0;
1811
$attr['acl_app_passwds'] = 0;
1812
}
1816
// save template
1817
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
1818
VALUES (:type, :template, :attributes)");
1819
$stmt->execute(array(
1820
":type" => "mailbox",
1821
":template" => $_data["template"],
1822
":attributes" => json_encode($attr)
1823
));
1825
// success
1826
$_SESSION['return'][] = array(
1827
'type' => 'success',
1828
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1829
'msg' => array('template_added', $_data["template"])
1830
);
1831
return true;
1832
break;
1833
}
1834
break;
1835
case 'edit':
1836
switch ($_type) {
1837
case 'alias_domain':
1838
$alias_domains = (array)$_data['alias_domain'];
1839
foreach ($alias_domains as $alias_domain) {
1840
$alias_domain = idn_to_ascii(strtolower(trim($alias_domain)), 0, INTL_IDNA_VARIANT_UTS46);
1841
$is_now = mailbox('get', 'alias_domain_details', $alias_domain);
1842
if (!empty($is_now)) {
1843
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
1844
$target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain'])), 0, INTL_IDNA_VARIANT_UTS46) : $is_now['target_domain'];
1845
}
1846
else {
1847
$_SESSION['return'][] = array(
1848
'type' => 'danger',
1849
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1850
'msg' => array('alias_domain_invalid', htmlspecialchars($alias_domain))
1851
);
1852
continue;
1853
}
1854
if (!is_valid_domain_name($target_domain)) {
1855
$_SESSION['return'][] = array(
1856
'type' => 'danger',
1857
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1858
'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1859
);
1860
continue;
1861
}
1862
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
1863
$_SESSION['return'][] = array(
1864
'type' => 'danger',
1865
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1866
'msg' => 'access_denied'
1867
);
1868
continue;
1869
}
1870
if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) {
1871
$_SESSION['return'][] = array(
1872
'type' => 'danger',
1873
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1874
'msg' => array('target_domain_invalid', htmlspecialchars($target_domain))
1875
);
1876
continue;
1877
}
1878
$stmt = $pdo->prepare("UPDATE `alias_domain` SET
1879
`target_domain` = :target_domain,
1880
`active` = :active
1881
WHERE `alias_domain` = :alias_domain");
1882
$stmt->execute(array(
1883
':alias_domain' => $alias_domain,
1884
':target_domain' => $target_domain,
1885
':active' => $active
1886
));
1887
$_SESSION['return'][] = array(
1888
'type' => 'success',
1889
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1890
'msg' => array('aliasd_modified', htmlspecialchars($alias_domain))
1891
);
1892
}
1893
break;
1894
case 'tls_policy':
1895
if (!is_array($_data['username'])) {
1896
$usernames = array();
1897
$usernames[] = $_data['username'];
1898
}
1899
else {
1900
$usernames = $_data['username'];
1901
}
1902
if (!hasACLAccess("tls_policy")) {
1903
$_SESSION['return'][] = array(
1904
'type' => 'danger',
1905
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1906
'msg' => 'access_denied'
1907
);
1908
return false;
1909
}
1910
foreach ($usernames as $username) {
1911
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1912
$_SESSION['return'][] = array(
1913
'type' => 'danger',
1914
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1915
'msg' => 'access_denied'
1916
);
1917
continue;
1918
}
1919
$is_now = mailbox('get', 'tls_policy', $username, $_extra);
1920
if (!empty($is_now)) {
1921
$tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
1922
$tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
1923
}
1924
else {
1925
$_SESSION['return'][] = array(
1926
'type' => 'danger',
1927
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1928
'msg' => 'access_denied'
1929
);
1930
continue;
1931
}
1932
$stmt = $pdo->prepare("UPDATE `mailbox`
1933
SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_out),
1934
`attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_in)
1935
WHERE `username` = :username");
1936
$stmt->execute(array(
1937
':tls_out' => intval($tls_enforce_out),
1938
':tls_in' => intval($tls_enforce_in),
1939
':username' => $username
1940
));
1941
$_SESSION['return'][] = array(
1942
'type' => 'success',
1943
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1944
'msg' => array('mailbox_modified', $username)
1945
);
1946
}
1947
break;
1948
case 'quarantine_notification':
1949
if (!is_array($_data['username'])) {
1950
$usernames = array();
1951
$usernames[] = $_data['username'];
1952
}
1953
else {
1954
$usernames = $_data['username'];
1955
}
1956
if (!hasACLAccess("quarantine_notification")) {
1957
$_SESSION['return'][] = array(
1958
'type' => 'danger',
1959
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1960
'msg' => 'access_denied'
1961
);
1962
return false;
1963
}
1964
foreach ($usernames as $username) {
1965
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
1966
$_SESSION['return'][] = array(
1967
'type' => 'danger',
1968
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1969
'msg' => 'access_denied'
1970
);
1971
continue;
1972
}
1973
$is_now = mailbox('get', 'quarantine_notification', $username, $_extra);
1974
if (!empty($is_now)) {
1975
$quarantine_notification = (isset($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
1976
}
1977
else {
1978
$_SESSION['return'][] = array(
1979
'type' => 'danger',
1980
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1981
'msg' => 'access_denied'
1982
);
1983
continue;
1984
}
1985
if (!in_array($quarantine_notification, array('never', 'hourly', 'daily', 'weekly'))) {
1986
$_SESSION['return'][] = array(
1987
'type' => 'danger',
1988
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
1989
'msg' => 'access_denied'
1990
);
1991
continue;
1992
}
1993
$stmt = $pdo->prepare("UPDATE `mailbox`
1994
SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', :quarantine_notification)
1995
WHERE `username` = :username");
1996
$stmt->execute(array(
1997
':quarantine_notification' => $quarantine_notification,
1998
':username' => $username
1999
));
2000
$_SESSION['return'][] = array(
2001
'type' => 'success',
2002
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2003
'msg' => array('mailbox_modified', $username)
2004
);
2005
}
2006
break;
2007
case 'quarantine_category':
2008
if (!is_array($_data['username'])) {
2009
$usernames = array();
2010
$usernames[] = $_data['username'];
2011
}
2012
else {
2013
$usernames = $_data['username'];
2014
}
2015
if (!hasACLAccess("quarantine_category")) {
2016
$_SESSION['return'][] = array(
2017
'type' => 'danger',
2018
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2019
'msg' => 'access_denied'
2020
);
2021
return false;
2022
}
2023
foreach ($usernames as $username) {
2024
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
2025
$_SESSION['return'][] = array(
2026
'type' => 'danger',
2027
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2028
'msg' => 'access_denied'
2029
);
2030
continue;
2031
}
2032
$is_now = mailbox('get', 'quarantine_category', $username, $_extra);
2033
if (!empty($is_now)) {
2034
$quarantine_category = (isset($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
2035
}
2036
else {
2037
$_SESSION['return'][] = array(
2038
'type' => 'danger',
2039
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2040
'msg' => 'access_denied'
2041
);
2042
continue;
2043
}
2044
if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
2045
$_SESSION['return'][] = array(
2046
'type' => 'danger',
2047
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2048
'msg' => 'access_denied'
2049
);
2050
continue;
2051
}
2052
$stmt = $pdo->prepare("UPDATE `mailbox`
2053
SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', :quarantine_category)
2054
WHERE `username` = :username");
2055
$stmt->execute(array(
2056
':quarantine_category' => $quarantine_category,
2057
':username' => $username
2058
));
2059
$_SESSION['return'][] = array(
2060
'type' => 'success',
2061
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2062
'msg' => array('mailbox_modified', $username)
2063
);
2064
}
2065
break;
2066
case 'spam_score':
2067
if (!is_array($_data['username'])) {
2068
$usernames = array();
2069
$usernames[] = $_data['username'];
2070
}
2071
else {
2072
$usernames = $_data['username'];
2073
}
2074
if (!isset($_SESSION['acl']['spam_score']) || $_SESSION['acl']['spam_score'] != "1" ) {
2075
$_SESSION['return'][] = array(
2076
'type' => 'danger',
2077
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2078
'msg' => 'access_denied'
2079
);
2080
return false;
2081
}
2082
foreach ($usernames as $username) {
2083
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
2084
$_SESSION['return'][] = array(
2085
'type' => 'danger',
2086
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2087
'msg' => 'access_denied'
2088
);
2089
continue;
2090
}
2091
if ($_data['spam_score'] == "default") {
2092
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
2093
AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
2094
$stmt->execute(array(
2095
':username' => $username
2096
));
2097
$_SESSION['return'][] = array(
2098
'type' => 'success',
2099
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2100
'msg' => array('mailbox_modified', $username)
2101
);
2102
continue;
2103
}
2104
$lowspamlevel = explode(',', $_data['spam_score'])[0];
2105
$highspamlevel = explode(',', $_data['spam_score'])[1];
2106
if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) {
2107
$_SESSION['return'][] = array(
2108
'type' => 'danger',
2109
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2110
'msg' => 'Invalid spam score, format must be "1,2" where first is low and second is high spam value.'
2111
);
2112
continue;
2113
}
2114
if ($lowspamlevel == $highspamlevel) {
2115
$highspamlevel = $highspamlevel + 0.1;
2116
}
2117
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
2118
AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
2119
$stmt->execute(array(
2120
':username' => $username
2121
));
2122
$stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
2123
VALUES (:username, 'highspamlevel', :highspamlevel)");
2124
$stmt->execute(array(
2125
':username' => $username,
2126
':highspamlevel' => $highspamlevel
2127
));
2128
$stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
2129
VALUES (:username, 'lowspamlevel', :lowspamlevel)");
2130
$stmt->execute(array(
2131
':username' => $username,
2132
':lowspamlevel' => $lowspamlevel
2133
));
2134
$_SESSION['return'][] = array(
2135
'type' => 'success',
2136
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2137
'msg' => array('mailbox_modified', $username)
2138
);
2139
}
2140
break;
2141
case 'time_limited_alias':
2142
if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
2143
$_SESSION['return'][] = array(
2144
'type' => 'danger',
2145
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2146
'msg' => 'access_denied'
2147
);
2148
return false;
2149
}
2150
if (!is_array($_data['address'])) {
2151
$addresses = array();
2152
$addresses[] = $_data['address'];
2153
}
2154
else {
2155
$addresses = $_data['address'];
2156
}
2157
foreach ($addresses as $address) {
2158
$stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
2159
$stmt->execute(array(':address' => $address));
2160
$goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
2161
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
2162
$_SESSION['return'][] = array(
2163
'type' => 'danger',
2164
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2165
'msg' => 'access_denied'
2166
);
2167
continue;
2168
}
2169
if (empty($_data['validity']) && empty($_data['permanent'])) {
2170
continue;
2171
}
2172
if (isset($_data['permanent']) && filter_var($_data['permanent'], FILTER_VALIDATE_BOOL)) {
2173
$permanent = 1;
2174
$validity = 0;
2175
}
2176
else if (isset($_data['validity'])) {
2177
$permanent = 0;
2178
$validity = round((int)time() + ($_data['validity'] * 3600));
2179
}
2180
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity, `permanent` = :permanent WHERE
2181
`address` = :address");
2182
$stmt->execute(array(
2183
':address' => $address,
2184
':validity' => $validity,
2185
':permanent' => $permanent
2186
));
2187
$_SESSION['return'][] = array(
2188
'type' => 'success',
2189
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2190
'msg' => array('mailbox_modified', htmlspecialchars(implode(', ', (array)$usernames)))
2191
);
2192
}
2193
break;
2194
case 'delimiter_action':
2195
if (!is_array($_data['username'])) {
2196
$usernames = array();
2197
$usernames[] = $_data['username'];
2198
}
2199
else {
2200
$usernames = $_data['username'];
2201
}
2202
if (!isset($_SESSION['acl']['delimiter_action']) || $_SESSION['acl']['delimiter_action'] != "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
foreach ($usernames as $username) {
2211
if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
2212
$_SESSION['return'][] = array(
2213
'type' => 'danger',
2214
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2215
'msg' => 'access_denied'
2216
);
2217
continue;
2218
}
2219
if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
2220
try {
2221
$redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
2222
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
2223
}
2224
catch (RedisException $e) {
2225
$_SESSION['return'][] = array(
2226
'type' => 'danger',
2227
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2228
'msg' => array('redis_error', $e)
2229
);
2230
continue;
2231
}
2232
}
2233
else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
2234
try {
2235
$redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
2236
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
2237
}
2238
catch (RedisException $e) {
2239
$_SESSION['return'][] = array(
2240
'type' => 'danger',
2241
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2242
'msg' => array('redis_error', $e)
2243
);
2244
continue;
2245
}
2246
}
2247
else {
2248
try {
2249
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
2250
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
2251
}
2252
catch (RedisException $e) {
2253
$_SESSION['return'][] = array(
2254
'type' => 'danger',
2255
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2256
'msg' => array('redis_error', $e)
2257
);
2258
continue;
2259
}
2260
}
2261
$_SESSION['return'][] = array(
2262
'type' => 'success',
2263
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2264
'msg' => array('mailbox_modified', $username)
2265
);
2266
}
2267
break;
2268
case 'syncjob':
2269
if (!is_array($_data['id'])) {
2270
$ids = array();
2271
$ids[] = $_data['id'];
2272
}
2273
else {
2274
$ids = $_data['id'];
2275
}
2276
if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
2277
$_SESSION['return'][] = array(
2278
'type' => 'danger',
2279
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2280
'msg' => 'access_denied'
2281
);
2282
return false;
2283
}
2284
foreach ($ids as $id) {
2285
$is_now = mailbox('get', 'syncjob_details', $id, array('with_password'));
2286
if (!empty($is_now)) {
2287
$username = $is_now['user2'];
2288
$user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1'];
2289
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2290
$last_run = (isset($_data['last_run'])) ? NULL : $is_now['last_run'];
2291
$success = (isset($_data['success'])) ? NULL : $is_now['success'];
2292
$delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates'];
2293
$subscribeall = (isset($_data['subscribeall'])) ? intval($_data['subscribeall']) : $is_now['subscribeall'];
2294
$dry = (isset($_data['dry'])) ? intval($_data['dry']) : $is_now['dry'];
2295
$delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1'];
2296
$delete2 = (isset($_data['delete2'])) ? intval($_data['delete2']) : $is_now['delete2'];
2297
$automap = (isset($_data['automap'])) ? intval($_data['automap']) : $is_now['automap'];
2298
$skipcrossduplicates = (isset($_data['skipcrossduplicates'])) ? intval($_data['skipcrossduplicates']) : $is_now['skipcrossduplicates'];
2299
$port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
2300
$password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
2301
$host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
2302
$subfolder2 = (isset($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
2303
$enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
2304
$mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
2305
$exclude = (isset($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
2306
$custom_params = (isset($_data['custom_params'])) ? $_data['custom_params'] : $is_now['custom_params'];
2307
$maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
2308
$maxbytespersecond = (isset($_data['maxbytespersecond']) && $_data['maxbytespersecond'] != "") ? intval($_data['maxbytespersecond']) : $is_now['maxbytespersecond'];
2309
$timeout1 = (isset($_data['timeout1']) && $_data['timeout1'] != "") ? intval($_data['timeout1']) : $is_now['timeout1'];
2310
$timeout2 = (isset($_data['timeout2']) && $_data['timeout2'] != "") ? intval($_data['timeout2']) : $is_now['timeout2'];
2311
}
2312
else {
2313
$_SESSION['return'][] = array(
2314
'type' => 'danger',
2315
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2316
'msg' => 'access_denied'
2317
);
2318
continue;
2319
}
2321
// validate custom params
2322
foreach (explode('-', $custom_params) as $param){
2323
if(empty($param)) continue;
2325
// extract option
2326
if (str_contains($param, '=')) $param = explode('=', $param)[0];
2327
else $param = rtrim($param, ' ');
2328
// remove first char if first char is -
2329
if ($param[0] == '-') $param = ltrim($param, $param[0]);
2331
if (str_contains($param, ' ')) {
2332
// bad char
2333
$_SESSION['return'][] = array(
2334
'type' => 'danger',
2335
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2336
'msg' => 'bad character SPACE'
2337
);
2338
return false;
2339
}
2341
// check if param is whitelisted
2342
if (!in_array(strtolower($param), $GLOBALS["IMAPSYNC_OPTIONS"]["whitelist"])){
2343
// bad option
2344
$_SESSION['return'][] = array(
2345
'type' => 'danger',
2346
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2347
'msg' => 'bad option '. $param
2348
);
2349
return false;
2350
}
2351
}
2352
if (empty($subfolder2)) {
2353
$subfolder2 = "";
2354
}
2355
if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2356
$maxage = "0";
2357
}
2358
if (!isset($timeout1) || !filter_var($timeout1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2359
$timeout1 = "600";
2360
}
2361
if (!isset($timeout2) || !filter_var($timeout2, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32000)))) {
2362
$timeout2 = "600";
2363
}
2364
if (!isset($maxbytespersecond) || !filter_var($maxbytespersecond, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 125000000)))) {
2365
$maxbytespersecond = "0";
2366
}
2367
if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
2368
$_SESSION['return'][] = array(
2369
'type' => 'danger',
2370
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2371
'msg' => 'access_denied'
2372
);
2373
continue;
2374
}
2375
if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 43800)))) {
2376
$_SESSION['return'][] = array(
2377
'type' => 'danger',
2378
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2379
'msg' => 'access_denied'
2380
);
2381
continue;
2382
}
2383
if (!is_valid_domain_name($host1)) {
2384
$_SESSION['return'][] = array(
2385
'type' => 'danger',
2386
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2387
'msg' => 'access_denied'
2388
);
2389
continue;
2390
}
2391
if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
2392
$_SESSION['return'][] = array(
2393
'type' => 'danger',
2394
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2395
'msg' => 'access_denied'
2396
);
2397
continue;
2398
}
2399
if (@preg_match("/" . $exclude . "/", null) === false) {
2400
$_SESSION['return'][] = array(
2401
'type' => 'danger',
2402
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2403
'msg' => 'access_denied'
2404
);
2405
continue;
2406
}
2407
$stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1,
2408
`delete2` = :delete2,
2409
`automap` = :automap,
2410
`skipcrossduplicates` = :skipcrossduplicates,
2411
`maxage` = :maxage,
2412
`maxbytespersecond` = :maxbytespersecond,
2413
`subfolder2` = :subfolder2,
2414
`exclude` = :exclude,
2415
`host1` = :host1,
2416
`last_run` = :last_run,
2417
`success` = :success,
2418
`user1` = :user1,
2419
`password1` = :password1,
2420
`mins_interval` = :mins_interval,
2421
`port1` = :port1,
2422
`enc1` = :enc1,
2423
`delete2duplicates` = :delete2duplicates,
2424
`custom_params` = :custom_params,
2425
`timeout1` = :timeout1,
2426
`timeout2` = :timeout2,
2427
`subscribeall` = :subscribeall,
2428
`dry` = :dry,
2429
`active` = :active
2430
WHERE `id` = :id");
2431
$stmt->execute(array(
2432
':delete1' => $delete1,
2433
':delete2' => $delete2,
2434
':automap' => $automap,
2435
':skipcrossduplicates' => $skipcrossduplicates,
2436
':id' => $id,
2437
':exclude' => $exclude,
2438
':maxage' => $maxage,
2439
':maxbytespersecond' => $maxbytespersecond,
2440
':subfolder2' => $subfolder2,
2441
':host1' => $host1,
2442
':user1' => $user1,
2443
':password1' => $password1,
2444
':last_run' => $last_run,
2445
':success' => $success,
2446
':mins_interval' => $mins_interval,
2447
':port1' => $port1,
2448
':enc1' => $enc1,
2449
':delete2duplicates' => $delete2duplicates,
2450
':custom_params' => $custom_params,
2451
':timeout1' => $timeout1,
2452
':timeout2' => $timeout2,
2453
':subscribeall' => $subscribeall,
2454
':dry' => $dry,
2455
':active' => $active,
2456
));
2457
$_SESSION['return'][] = array(
2458
'type' => 'success',
2459
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2460
'msg' => array('mailbox_modified', $username)
2461
);
2462
}
2463
break;
2464
case 'filter':
2465
if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
2466
$_SESSION['return'][] = array(
2467
'type' => 'danger',
2468
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2469
'msg' => 'access_denied'
2470
);
2471
return false;
2472
}
2473
$sieve = new Sieve\SieveParser();
2474
if (!is_array($_data['id'])) {
2475
$ids = array();
2476
$ids[] = $_data['id'];
2477
}
2478
else {
2479
$ids = $_data['id'];
2480
}
2481
foreach ($ids as $id) {
2482
$is_now = mailbox('get', 'filter_details', $id);
2483
if (!empty($is_now)) {
2484
$username = $is_now['username'];
2485
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2486
$script_desc = (!empty($_data['script_desc'])) ? $_data['script_desc'] : $is_now['script_desc'];
2487
$script_data = (!empty($_data['script_data'])) ? $_data['script_data'] : $is_now['script_data'];
2488
$filter_type = (!empty($_data['filter_type'])) ? $_data['filter_type'] : $is_now['filter_type'];
2489
}
2490
else {
2491
$_SESSION['return'][] = array(
2492
'type' => 'danger',
2493
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2494
'msg' => 'access_denied'
2495
);
2496
continue;
2497
}
2498
try {
2499
$sieve->parse($script_data);
2500
}
2501
catch (Exception $e) {
2502
$_SESSION['return'][] = array(
2503
'type' => 'danger',
2504
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2505
'msg' => array('sieve_error', $e->getMessage())
2506
);
2507
continue;
2508
}
2509
if ($filter_type != 'postfilter' && $filter_type != 'prefilter') {
2510
$_SESSION['return'][] = array(
2511
'type' => 'danger',
2512
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2513
'msg' => 'filter_type'
2514
);
2515
continue;
2516
}
2517
if ($active == '1') {
2518
$script_name = 'active';
2519
$stmt = $pdo->prepare("UPDATE `sieve_filters`
2520
SET `script_name` = 'inactive'
2521
WHERE `username` = :username
2522
AND `filter_type` = :filter_type");
2523
$stmt->execute(array(
2524
':username' => $username,
2525
':filter_type' => $filter_type
2526
));
2527
}
2528
else {
2529
$script_name = 'inactive';
2530
}
2531
$stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_desc` = :script_desc, `script_data` = :script_data, `script_name` = :script_name, `filter_type` = :filter_type
2532
WHERE `id` = :id");
2533
$stmt->execute(array(
2534
':script_desc' => $script_desc,
2535
':script_data' => $script_data,
2536
':script_name' => $script_name,
2537
':filter_type' => $filter_type,
2538
':id' => $id
2539
));
2540
$_SESSION['return'][] = array(
2541
'type' => 'success',
2542
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2543
'msg' => array('mailbox_modified', $username)
2544
);
2545
}
2546
break;
2547
case 'alias':
2548
if (!is_array($_data['id'])) {
2549
$ids = array();
2550
$ids[] = $_data['id'];
2551
}
2552
else {
2553
$ids = $_data['id'];
2554
}
2555
foreach ($ids as $id) {
2556
$is_now = mailbox('get', 'alias_details', $id);
2557
if (!empty($is_now)) {
2558
$internal = (isset($_data['internal'])) ? intval($_data['internal']) : $is_now['internal'];
2559
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2560
$sender_allowed = (isset($_data['sender_allowed'])) ? intval($_data['sender_allowed']) : $is_now['sender_allowed'];
2561
$sogo_visible = (isset($_data['sogo_visible'])) ? intval($_data['sogo_visible']) : $is_now['sogo_visible'];
2562
$goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
2563
$goto_spam = (isset($_data['goto_spam'])) ? intval($_data['goto_spam']) : 0;
2564
$goto_ham = (isset($_data['goto_ham'])) ? intval($_data['goto_ham']) : 0;
2565
$public_comment = (isset($_data['public_comment'])) ? $_data['public_comment'] : $is_now['public_comment'];
2566
$private_comment = (isset($_data['private_comment'])) ? $_data['private_comment'] : $is_now['private_comment'];
2567
$goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
2568
$address = (!empty($_data['address'])) ? $_data['address'] : $is_now['address'];
2569
}
2570
else {
2571
$_SESSION['return'][] = array(
2572
'type' => 'danger',
2573
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2574
'msg' => array('alias_invalid', $address)
2575
);
2576
continue;
2577
}
2578
if ($_data['expand_alias'] === true || $_data['expand_alias'] == 1) {
2579
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
2580
WHERE `address` = :address
2581
AND `domain` NOT IN (
2582
SELECT `alias_domain` FROM `alias_domain`
2583
)");
2584
$stmt->execute(array(
2585
':address' => $address,
2586
));
2587
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2588
if ($num_results == 0) {
2589
$_SESSION['return'][] = array(
2590
'type' => 'warning',
2591
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2592
'msg' => array('is_not_primary_alias', htmlspecialchars($address))
2593
);
2594
continue;
2595
}
2596
$stmt = $pdo->prepare("SELECT `goto`, GROUP_CONCAT(CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`)) AS `missing_alias`
2597
FROM `alias` JOIN `alias_domain` ON `alias_domain`.`target_domain` = `alias`.`domain`
2598
WHERE CONCAT(SUBSTRING(`alias`.`address`, 1, LOCATE('@', `alias`.`address`) - 1), '@', `alias_domain`.`alias_domain`) NOT IN (
2599
SELECT `address` FROM `alias` WHERE `address` != `goto`
2600
)
2601
AND `alias`.`address` NOT IN (
2602
SELECT `address` FROM `alias` WHERE `address` = `goto`
2603
)
2604
AND `address` = :address ;");
2605
$stmt->execute(array(
2606
':address' => $address
2607
));
2608
$missing_aliases = $stmt->fetch(PDO::FETCH_ASSOC);
2609
if (!empty($missing_aliases['missing_alias'])) {
2610
mailbox('add', 'alias', array(
2611
'address' => $missing_aliases['missing_alias'],
2612
'goto' => $missing_aliases['goto'],
2613
'sogo_visible' => 1,
2614
'active' => 1
2615
));
2616
}
2617
$_SESSION['return'][] = array(
2618
'type' => 'success',
2619
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2620
'msg' => array('alias_modified', htmlspecialchars($address))
2621
);
2622
continue;
2623
}
2624
$domain = idn_to_ascii(substr(strstr($address, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
2625
if ($is_now['address'] != $address) {
2626
$local_part = strstr($address, '@', true);
2627
$address = $local_part.'@'.$domain;
2628
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2629
$_SESSION['return'][] = array(
2630
'type' => 'danger',
2631
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2632
'msg' => 'access_denied'
2633
);
2634
continue;
2635
}
2636
if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
2637
$_SESSION['return'][] = array(
2638
'type' => 'danger',
2639
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2640
'msg' => array('alias_invalid', $address)
2641
);
2642
continue;
2643
}
2644
if (strtolower($is_now['address']) != strtolower($address)) {
2645
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
2646
WHERE `address`= :address OR `address` IN (
2647
SELECT `username` FROM `mailbox`, `alias_domain`
2648
WHERE (
2649
`alias_domain`.`alias_domain` = :address_d
2650
AND `mailbox`.`username` = CONCAT(:address_l, '@', alias_domain.target_domain)))");
2651
$stmt->execute(array(
2652
':address' => $address,
2653
':address_l' => $local_part,
2654
':address_d' => $domain
2655
));
2656
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2657
if ($num_results != 0) {
2658
$_SESSION['return'][] = array(
2659
'type' => 'danger',
2660
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2661
'msg' => array('is_alias_or_mailbox', htmlspecialchars($address))
2662
);
2663
continue;
2664
}
2665
}
2666
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
2667
WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
2668
$stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
2669
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2670
if ($num_results == 0) {
2671
$_SESSION['return'][] = array(
2672
'type' => 'danger',
2673
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2674
'msg' => array('domain_not_found', htmlspecialchars($domain))
2675
);
2676
continue;
2677
}
2678
$stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
2679
WHERE `address`= :address");
2680
$stmt->execute(array(':address' => $address));
2681
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
2682
if ($num_results != 0) {
2683
$_SESSION['return'][] = array(
2684
'type' => 'danger',
2685
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2686
'msg' => array('is_spam_alias', htmlspecialchars($address))
2687
);
2688
continue;
2689
}
2690
}
2691
if ($goto_null == "1") {
2692
$goto = "null@localhost";
2693
}
2694
elseif ($goto_spam == "1") {
2695
$goto = "spam@localhost";
2696
}
2697
elseif ($goto_ham == "1") {
2698
$goto = "ham@localhost";
2699
}
2700
else {
2701
$gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $goto));
2702
foreach ($gotos as $i => &$goto) {
2703
if (empty($goto)) {
2704
continue;
2705
}
2706
if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) {
2707
$_SESSION['return'][] = array(
2708
'type' => 'danger',
2709
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2710
'msg' => array('goto_invalid', $goto)
2711
);
2712
unset($gotos[$i]);
2713
continue;
2714
}
2715
if ($goto == $address) {
2716
$_SESSION['return'][] = array(
2717
'type' => 'danger',
2718
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2719
'msg' => 'alias_goto_identical'
2720
);
2721
unset($gotos[$i]);
2722
continue;
2723
}
2724
// Delete from sender_acl to prevent duplicates
2725
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE
2726
`logged_in_as` = :goto AND
2727
`send_as` = :address");
2728
$stmt->execute(array(
2729
':goto' => $goto,
2730
':address' => $address
2731
));
2732
}
2733
$gotos = array_unique($gotos);
2734
$gotos = array_filter($gotos);
2735
$goto = implode(",", (array)$gotos);
2736
}
2737
if (!empty($goto)) {
2738
$stmt = $pdo->prepare("UPDATE `alias` SET
2739
`address` = :address,
2740
`public_comment` = :public_comment,
2741
`private_comment` = :private_comment,
2742
`domain` = :domain,
2743
`goto` = :goto,
2744
`sogo_visible`= :sogo_visible,
2745
`internal`= :internal,
2746
`sender_allowed`= :sender_allowed,
2747
`active`= :active
2748
WHERE `id` = :id");
2749
$stmt->execute(array(
2750
':address' => $address,
2751
':public_comment' => $public_comment,
2752
':private_comment' => $private_comment,
2753
':domain' => $domain,
2754
':goto' => $goto,
2755
':sogo_visible' => $sogo_visible,
2756
':internal' => $internal,
2757
':sender_allowed' => $sender_allowed,
2758
':active' => $active,
2759
':id' => $is_now['id']
2760
));
2761
}
2762
$_SESSION['return'][] = array(
2763
'type' => 'success',
2764
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2765
'msg' => array('alias_modified', htmlspecialchars($address))
2766
);
2768
// Track affected mailboxes for SOGo update (both old and new goto addresses)
2769
// Old goto: to remove alias from their view
2770
if (!empty($is_now['goto'])) {
2771
$old_gotos = array_map('trim', explode(',', $is_now['goto']));
2772
foreach ($old_gotos as $g) {
2773
if (filter_var($g, FILTER_VALIDATE_EMAIL) &&
2774
!in_array($g, array('null@localhost', 'spam@localhost', 'ham@localhost'))) {
2775
$update_sogo_mailboxes[] = $g;
2776
}
2777
}
2778
}
2779
// New goto: to add alias to their view
2780
if (!empty($goto)) {
2781
$new_gotos = array_map('trim', explode(',', $goto));
2782
foreach ($new_gotos as $g) {
2783
if (filter_var($g, FILTER_VALIDATE_EMAIL) &&
2784
!in_array($g, array('null@localhost', 'spam@localhost', 'ham@localhost'))) {
2785
$update_sogo_mailboxes[] = $g;
2786
}
2787
}
2788
}
2789
}
2790
break;
2791
case 'domain':
2792
if (!is_array($_data['domain'])) {
2793
$domains = array();
2794
$domains[] = $_data['domain'];
2795
}
2796
else {
2797
$domains = $_data['domain'];
2798
}
2799
foreach ($domains as $domain) {
2800
$domain = idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
2801
if (!is_valid_domain_name($domain)) {
2802
$_SESSION['return'][] = array(
2803
'type' => 'danger',
2804
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2805
'msg' => 'domain_invalid'
2806
);
2807
continue;
2808
}
2809
if ($_SESSION['mailcow_cc_role'] == "domainadmin" &&
2810
hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
2811
$is_now = mailbox('get', 'domain_details', $domain);
2812
if (!empty($is_now)) {
2813
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2814
$description = (!empty($_data['description']) && isset($_SESSION['acl']['domain_desc']) && $_SESSION['acl']['domain_desc'] == "1") ? $_data['description'] : $is_now['description'];
2815
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['domain_relayhost']) && $_SESSION['acl']['domain_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['relayhost']);
2816
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
2817
}
2818
else {
2819
$_SESSION['return'][] = array(
2820
'type' => 'danger',
2821
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2822
'msg' => 'domain_invalid'
2823
);
2824
continue;
2825
}
2827
$stmt = $pdo->prepare("UPDATE `domain` SET
2828
`description` = :description,
2829
`gal` = :gal
2830
WHERE `domain` = :domain");
2831
$stmt->execute(array(
2832
':description' => $description,
2833
':gal' => $gal,
2834
':domain' => $domain
2835
));
2836
// save tags
2837
foreach($tags as $index => $tag){
2838
if (empty($tag)) continue;
2839
if ($index > $GLOBALS['TAGGING_LIMIT']) {
2840
$_SESSION['return'][] = array(
2841
'type' => 'warning',
2842
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2843
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
2844
);
2845
break;
2846
}
2847
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
2848
$stmt->execute(array(
2849
':domain' => $domain,
2850
':tag_name' => $tag,
2851
));
2852
}
2854
$_SESSION['return'][] = array(
2855
'type' => 'success',
2856
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2857
'msg' => array('domain_modified', htmlspecialchars($domain))
2858
);
2859
}
2860
elseif ($_SESSION['mailcow_cc_role'] == "admin") {
2861
$is_now = mailbox('get', 'domain_details', $domain);
2862
if (!empty($is_now)) {
2863
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
2864
$backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx'];
2865
$gal = (isset($_data['gal'])) ? intval($_data['gal']) : $is_now['gal'];
2866
$relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients'];
2867
$relay_unknown_only = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : $is_now['relay_unknown_only'];
2868
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : $is_now['relayhost'];
2869
$aliases = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain'];
2870
$mailboxes = (isset($_data['mailboxes']) && $_data['mailboxes'] != '') ? intval($_data['mailboxes']) : $is_now['max_num_mboxes_for_domain'];
2871
$defquota = (isset($_data['defquota']) && $_data['defquota'] != '') ? intval($_data['defquota']) : ($is_now['def_quota_for_mbox'] / 1048576);
2872
$maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576);
2873
$quota = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
2874
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
2875
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
2876
if ($relay_all_recipients == '1') {
2877
$backupmx = '1';
2878
}
2879
if ($relay_unknown_only == '1') {
2880
$backupmx = '1';
2881
$relay_all_recipients = '1';
2882
}
2883
}
2884
else {
2885
$_SESSION['return'][] = array(
2886
'type' => 'danger',
2887
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2888
'msg' => 'domain_invalid'
2889
);
2890
continue;
2891
}
2892
// todo: should be using api here
2893
$stmt = $pdo->prepare("SELECT
2894
COUNT(*) AS count,
2895
MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
2896
COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
2897
FROM `mailbox`
2898
WHERE (`kind` = '' OR `kind` = NULL)
2899
AND domain = :domain");
2900
$stmt->execute(array(':domain' => $domain));
2901
$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
2902
// todo: should be using api here
2903
$stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
2904
WHERE domain = :domain
2905
AND address NOT IN (
2906
SELECT `username` FROM `mailbox`
2907
)");
2908
$stmt->execute(array(':domain' => $domain));
2909
$AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
2910
if ($defquota > $maxquota) {
2911
$_SESSION['return'][] = array(
2912
'type' => 'danger',
2913
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2914
'msg' => 'mailbox_defquota_exceeds_mailbox_maxquota'
2915
);
2916
continue;
2917
}
2918
if ($defquota == "0" || empty($defquota)) {
2919
$_SESSION['return'][] = array(
2920
'type' => 'danger',
2921
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2922
'msg' => 'defquota_empty'
2923
);
2924
continue;
2925
}
2926
if ($maxquota > $quota) {
2927
$_SESSION['return'][] = array(
2928
'type' => 'danger',
2929
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2930
'msg' => 'mailbox_quota_exceeds_domain_quota'
2931
);
2932
continue;
2933
}
2934
if ($maxquota == "0" || empty($maxquota)) {
2935
$_SESSION['return'][] = array(
2936
'type' => 'danger',
2937
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2938
'msg' => 'maxquota_empty'
2939
);
2940
continue;
2941
}
2942
if ($MailboxData['biggest_mailbox'] > $maxquota) {
2943
$_SESSION['return'][] = array(
2944
'type' => 'danger',
2945
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2946
'msg' => array('max_quota_in_use', $MailboxData['biggest_mailbox'])
2947
);
2948
continue;
2949
}
2950
if ($MailboxData['quota_all'] > $quota) {
2951
$_SESSION['return'][] = array(
2952
'type' => 'danger',
2953
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2954
'msg' => array('domain_quota_m_in_use', $MailboxData['quota_all'])
2955
);
2956
continue;
2957
}
2958
if ($MailboxData['count'] > $mailboxes) {
2959
$_SESSION['return'][] = array(
2960
'type' => 'danger',
2961
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2962
'msg' => array('mailboxes_in_use', $MailboxData['count'])
2963
);
2964
continue;
2965
}
2966
if ($AliasData['count'] > $aliases) {
2967
$_SESSION['return'][] = array(
2968
'type' => 'danger',
2969
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
2970
'msg' => array('aliases_in_use', $AliasData['count'])
2971
);
2972
continue;
2973
}
2975
$stmt = $pdo->prepare("UPDATE `domain` SET
2976
`relay_all_recipients` = :relay_all_recipients,
2977
`relay_unknown_only` = :relay_unknown_only,
2978
`backupmx` = :backupmx,
2979
`gal` = :gal,
2980
`active` = :active,
2981
`quota` = :quota,
2982
`defquota` = :defquota,
2983
`maxquota` = :maxquota,
2984
`relayhost` = :relayhost,
2985
`mailboxes` = :mailboxes,
2986
`aliases` = :aliases,
2987
`description` = :description
2988
WHERE `domain` = :domain");
2989
$stmt->execute(array(
2990
':relay_all_recipients' => $relay_all_recipients,
2991
':relay_unknown_only' => $relay_unknown_only,
2992
':backupmx' => $backupmx,
2993
':gal' => $gal,
2994
':active' => $active,
2995
':quota' => $quota,
2996
':defquota' => $defquota,
2997
':maxquota' => $maxquota,
2998
':relayhost' => $relayhost,
2999
':mailboxes' => $mailboxes,
3000
':aliases' => $aliases,
3001
':description' => $description,
3002
':domain' => $domain
3003
));
3004
// save tags
3005
foreach($tags as $index => $tag){
3006
if (empty($tag)) continue;
3007
if ($index > $GLOBALS['TAGGING_LIMIT']) {
3008
$_SESSION['return'][] = array(
3009
'type' => 'warning',
3010
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3011
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
3012
);
3013
break;
3014
}
3015
$stmt = $pdo->prepare("INSERT INTO `tags_domain` (`domain`, `tag_name`) VALUES (:domain, :tag_name)");
3016
$stmt->execute(array(
3017
':domain' => $domain,
3018
':tag_name' => $tag,
3019
));
3020
}
3022
$_SESSION['return'][] = array(
3023
'type' => 'success',
3024
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3025
'msg' => array('domain_modified', htmlspecialchars($domain))
3026
);
3027
}
3028
}
3029
break;
3030
case 'domain_templates':
3031
if ($_SESSION['mailcow_cc_role'] != "admin") {
3032
$_SESSION['return'][] = array(
3033
'type' => 'danger',
3034
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3035
'msg' => 'access_denied'
3036
);
3037
return false;
3038
}
3039
if (!is_array($_data['ids'])) {
3040
$ids = array();
3041
$ids[] = $_data['ids'];
3042
}
3043
else {
3044
$ids = $_data['ids'];
3045
}
3046
foreach ($ids as $id) {
3047
$is_now = mailbox("get", "domain_templates", $id);
3048
if (empty($is_now) ||
3049
$is_now["type"] != "domain"){
3050
$_SESSION['return'][] = array(
3051
'type' => 'danger',
3052
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3053
'msg' => 'template_id_invalid'
3054
);
3055
continue;
3056
}
3058
// check name
3059
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
3060
// keep template name of Default template
3061
$_data["template"] = $is_now["template"];
3062
}
3063
else {
3064
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
3065
}
3066
// check attributes
3067
$attr = array();
3068
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
3069
$attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
3070
$attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
3071
$attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
3072
$attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
3073
$attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
3074
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
3075
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
3076
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
3077
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
3078
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
3079
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
3080
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
3081
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
3082
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
3084
// update template
3085
$stmt = $pdo->prepare("UPDATE `templates`
3086
SET `template` = :template, `attributes` = :attributes
3087
WHERE id = :id");
3088
$stmt->execute(array(
3089
":id" => $id ,
3090
":template" => $_data["template"] ,
3091
":attributes" => json_encode($attr)
3092
));
3093
}
3096
$_SESSION['return'][] = array(
3097
'type' => 'success',
3098
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3099
'msg' => array('template_modified', $_data["template"])
3100
);
3101
return true;
3102
break;
3103
case 'mailbox':
3104
if (!is_array($_data['username'])) {
3105
$usernames = array();
3106
$usernames[] = $_data['username'];
3107
}
3108
else {
3109
$usernames = $_data['username'];
3110
}
3111
foreach ($usernames as $username) {
3112
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
3113
$_SESSION['return'][] = array(
3114
'type' => 'danger',
3115
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3116
'msg' => array('username_invalid', $username)
3117
);
3118
continue;
3119
}
3120
$is_now = mailbox('get', 'mailbox_details', $username, $_extra);
3121
if (isset($_data['protocol_access'])) {
3122
$_data['protocol_access'] = (array)$_data['protocol_access'];
3123
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
3124
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
3125
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
3126
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
3127
$_data['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
3128
$_data['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
3129
}
3130
if (!empty($is_now)) {
3131
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
3132
(int)$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($is_now['attributes']['force_pw_update']);
3133
(int)$force_tfa = (isset($_data['force_tfa'])) ? intval($_data['force_tfa']) : intval($is_now['attributes']['force_tfa']);
3134
(int)$sogo_access = (isset($_data['sogo_access']) && hasACLAccess("sogo_access")) ? intval($_data['sogo_access']) : intval($is_now['attributes']['sogo_access']);
3135
(int)$imap_access = (isset($_data['imap_access']) && hasACLAccess("protocol_access")) ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
3136
(int)$pop3_access = (isset($_data['pop3_access']) && hasACLAccess("protocol_access")) ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
3137
(int)$smtp_access = (isset($_data['smtp_access']) && hasACLAccess("protocol_access")) ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
3138
(int)$sieve_access = (isset($_data['sieve_access']) && hasACLAccess("protocol_access")) ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
3139
(int)$eas_access = (isset($_data['eas_access']) && hasACLAccess("protocol_access")) ? intval($_data['eas_access']) : intval($is_now['attributes']['eas_access']);
3140
(int)$dav_access = (isset($_data['dav_access']) && hasACLAccess("protocol_access")) ? intval($_data['dav_access']) : intval($is_now['attributes']['dav_access']);
3141
(int)$relayhost = (isset($_data['relayhost']) && hasACLAccess("mailbox_relayhost")) ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
3142
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
3143
$name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
3144
$domain = $is_now['domain'];
3145
$quota_b = $quota_m * 1048576;
3146
$password = (!empty($_data['password'])) ? $_data['password'] : null;
3147
$password2 = (!empty($_data['password2'])) ? $_data['password2'] : null;
3148
$tags = (is_array($_data['tags']) ? $_data['tags'] : array());
3149
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
3150
$authsource = $is_now['authsource'];
3151
if ($_data['authsource'] == "mailcow" ||
3152
in_array($_data['authsource'], array('keycloak', 'generic-oidc', 'ldap')) && $iam_settings['authsource'] == $_data['authsource']){
3153
$authsource = $_data['authsource'];
3154
}
3155
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
3156
$force_pw_update = 0;
3157
}
3158
if ($authsource == 'generic-oidc'){
3159
$force_tfa = 0;
3160
}
3161
$pw_recovery_email = (isset($_data['pw_recovery_email']) && $authsource == 'mailcow') ? $_data['pw_recovery_email'] : $is_now['attributes']['recovery_email'];
3162
}
3163
else {
3164
$_SESSION['return'][] = array(
3165
'type' => 'danger',
3166
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3167
'msg' => 'access_denied'
3168
);
3169
continue;
3170
}
3171
// if already 0 == ok
3172
if (!hasACLAccess("unlimited_quota") && ($quota_m == 0 && $is_now['quota'] != 0)) {
3173
$_SESSION['return'][] = array(
3174
'type' => 'danger',
3175
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3176
'msg' => 'unlimited_quota_acl'
3177
);
3178
return false;
3179
}
3180
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3181
$_SESSION['return'][] = array(
3182
'type' => 'danger',
3183
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3184
'msg' => 'access_denied'
3185
);
3186
continue;
3187
}
3188
$DomainData = mailbox('get', 'domain_details', $domain, $_extra);
3189
if ($quota_m > ($is_now['max_new_quota'] / 1048576)) {
3190
$_SESSION['return'][] = array(
3191
'type' => 'danger',
3192
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3193
'msg' => array('mailbox_quota_left_exceeded', ($is_now['max_new_quota'] / 1048576))
3194
);
3195
continue;
3196
}
3197
if ($quota_m > $DomainData['max_quota_for_mbox']) {
3198
$_SESSION['return'][] = array(
3199
'type' => 'danger',
3200
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3201
'msg' => array('mailbox_quota_exceeded', $DomainData['max_quota_for_mbox'])
3202
);
3203
continue;
3204
}
3205
$extra_acls = array();
3206
if (isset($_data['extended_sender_acl'])) {
3207
if (!hasACLAccess("extend_sender_acl")) {
3208
$_SESSION['return'][] = array(
3209
'type' => 'danger',
3210
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3211
'msg' => 'extended_sender_acl_denied'
3212
);
3213
}
3214
else {
3215
$extra_acls = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['extended_sender_acl']));
3216
foreach ($extra_acls as $i => &$extra_acl) {
3217
if (empty($extra_acl)) {
3218
continue;
3219
}
3220
if (substr($extra_acl, 0, 1) === "@") {
3221
$extra_acl = ltrim($extra_acl, '@');
3222
}
3223
if (!filter_var($extra_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($extra_acl)) {
3224
$_SESSION['return'][] = array(
3225
'type' => 'danger',
3226
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3227
'msg' => array('extra_acl_invalid', htmlspecialchars($extra_acl))
3228
);
3229
unset($extra_acls[$i]);
3230
continue;
3231
}
3232
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
3233
if (filter_var($extra_acl, FILTER_VALIDATE_EMAIL)) {
3234
$extra_acl_domain = idn_to_ascii(substr(strstr($extra_acl, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
3235
if (in_array($extra_acl_domain, $domains)) {
3236
$_SESSION['return'][] = array(
3237
'type' => 'danger',
3238
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3239
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
3240
);
3241
unset($extra_acls[$i]);
3242
continue;
3243
}
3244
}
3245
else {
3246
if (in_array($extra_acl, $domains)) {
3247
$_SESSION['return'][] = array(
3248
'type' => 'danger',
3249
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3250
'msg' => array('extra_acl_invalid_domain', $extra_acl_domain)
3251
);
3252
unset($extra_acls[$i]);
3253
continue;
3254
}
3255
$extra_acl = '@' . $extra_acl;
3256
}
3257
}
3258
$extra_acls = array_filter($extra_acls);
3259
$extra_acls = array_values($extra_acls);
3260
$extra_acls = array_unique($extra_acls);
3261
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 1 AND `logged_in_as` = :username");
3262
$stmt->execute(array(
3263
':username' => $username
3264
));
3265
foreach ($extra_acls as $sender_acl_external) {
3266
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`, `external`)
3267
VALUES (:sender_acl, :username, 1)");
3268
$stmt->execute(array(
3269
':sender_acl' => $sender_acl_external,
3270
':username' => $username
3271
));
3272
}
3273
}
3274
}
3275
if (isset($_data['sender_acl'])) {
3276
// Get sender_acl items set by admin
3277
$current_sender_acls = mailbox('get', 'sender_acl_handles', $username);
3278
$sender_acl_admin = array_merge(
3279
$current_sender_acls['sender_acl_domains']['ro'],
3280
$current_sender_acls['sender_acl_addresses']['ro']
3281
);
3282
// Get sender_acl items from POST array
3283
// Set sender_acl_domain_admin to empty array if sender_acl contains "default" to trigger a reset
3284
// Delete records from sender_acl if sender_acl contains "*" and set to array("*")
3285
$_data['sender_acl'] = (array)$_data['sender_acl'];
3286
if (in_array("*", $_data['sender_acl'])) {
3287
$sender_acl_domain_admin = array('*');
3288
}
3289
elseif (array("default") === $_data['sender_acl']) {
3290
$sender_acl_domain_admin = array();
3291
}
3292
else {
3293
if (array_search('default', $_data['sender_acl']) !== false){
3294
unset($_data['sender_acl'][array_search('default', $_data['sender_acl'])]);
3295
}
3296
$sender_acl_domain_admin = $_data['sender_acl'];
3297
}
3298
if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) {
3299
// Check items in POST array and skip invalid
3300
foreach ($sender_acl_domain_admin as $key => $val) {
3301
// Check for invalid domain or email format or not *
3302
if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@')) && $val != '*') {
3303
$_SESSION['return'][] = array(
3304
'type' => 'danger',
3305
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3306
'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3307
);
3308
unset($sender_acl_domain_admin[$key]);
3309
continue;
3310
}
3311
// Check if user has domain access (if object is domain)
3312
$domain = ltrim($sender_acl_domain_admin[$key], '@');
3313
if (is_valid_domain_name($domain)) {
3314
// Check for- and skip non-mailcow domains
3315
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
3316
if (!empty($domains)) {
3317
if (!in_array($domain, $domains)) {
3318
$_SESSION['return'][] = array(
3319
'type' => 'danger',
3320
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3321
'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3322
);
3323
unset($sender_acl_domain_admin[$key]);
3324
continue;
3325
}
3326
}
3327
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3328
$_SESSION['return'][] = array(
3329
'type' => 'danger',
3330
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3331
'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3332
);
3333
unset($sender_acl_domain_admin[$key]);
3334
continue;
3335
}
3336
}
3337
// Wildcard can only be used if role == admin
3338
if ($val == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
3339
$_SESSION['return'][] = array(
3340
'type' => 'danger',
3341
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3342
'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3343
);
3344
unset($sender_acl_domain_admin[$key]);
3345
continue;
3346
}
3347
// Check if user has alias access (if object is email)
3348
if (filter_var($val, FILTER_VALIDATE_EMAIL)) {
3349
if (!hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) {
3350
$_SESSION['return'][] = array(
3351
'type' => 'danger',
3352
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3353
'msg' => array('sender_acl_invalid', $sender_acl_domain_admin[$key])
3354
);
3355
unset($sender_acl_domain_admin[$key]);
3356
continue;
3357
}
3358
}
3359
}
3360
// Merge both arrays
3361
$sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin);
3362
// If merged array still contains "*", set it as only value
3363
!in_array('*', $sender_acl_merged) ?: $sender_acl_merged = array('*');
3364
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3365
$stmt->execute(array(
3366
':username' => $username
3367
));
3368
$sender_acl_handles = mailbox('get', 'sender_acl_handles', $username);
3369
$fixed_sender_aliases_allowed = $sender_acl_handles['fixed_sender_aliases_allowed'];
3370
$fixed_sender_aliases_blocked = $sender_acl_handles['fixed_sender_aliases_blocked'];
3372
foreach ($sender_acl_merged as $sender_acl) {
3373
$domain = ltrim($sender_acl, '@');
3374
if (is_valid_domain_name($domain)) {
3375
$sender_acl = '@' . $domain;
3376
}
3378
// Always add to sender_acl table to create explicit permission
3379
// Skip only if it's in allowed list (would be redundant)
3380
// But DO add if it's in blocked list (creates override)
3381
if (in_array($sender_acl, $fixed_sender_aliases_allowed)) {
3382
// Skip: already allowed by sender_allowed=1, no need for sender_acl entry
3383
continue;
3384
}
3386
// Add to sender_acl (either override for blocked aliases, or grant for selectable ones)
3387
$stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`)
3388
VALUES (:sender_acl, :username)");
3389
$stmt->execute(array(
3390
':sender_acl' => $sender_acl,
3391
':username' => $username
3392
));
3393
}
3394
}
3395
else {
3396
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `external` = 0 AND `logged_in_as` = :username");
3397
$stmt->execute(array(
3398
':username' => $username
3399
));
3400
}
3401
}
3402
if (!empty($password)) {
3403
if (password_check($password, $password2) !== true) {
3404
continue;
3405
}
3406
$password_hashed = hash_password($password);
3407
$stmt = $pdo->prepare("UPDATE `mailbox` SET
3408
`password` = :password_hashed,
3409
`attributes` = JSON_SET(`attributes`, '$.passwd_update', NOW())
3410
WHERE `username` = :username AND authsource = 'mailcow'");
3411
$stmt->execute(array(
3412
':password_hashed' => $password_hashed,
3413
':username' => $username
3414
));
3415
}
3416
// 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)
3417
$stmt = $pdo->prepare("UPDATE `alias` SET
3418
`active` = :active
3419
WHERE `address` = :address");
3420
$stmt->execute(array(
3421
':address' => $username,
3422
':active' => $active
3423
));
3424
try {
3425
$stmt = $pdo->prepare("UPDATE `mailbox` SET
3426
`active` = :active,
3427
`name`= :name,
3428
`quota` = :quota_b,
3429
`authsource` = :authsource,
3430
`attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
3431
`attributes` = JSON_SET(`attributes`, '$.force_tfa', :force_tfa),
3432
`attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
3433
`attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
3434
`attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
3435
`attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
3436
`attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
3437
`attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access),
3438
`attributes` = JSON_SET(`attributes`, '$.eas_access', :eas_access),
3439
`attributes` = JSON_SET(`attributes`, '$.dav_access', :dav_access),
3440
`attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email),
3441
`attributes` = JSON_SET(`attributes`, '$.attribute_hash', :attribute_hash)
3442
WHERE `username` = :username");
3443
$stmt->execute(array(
3444
':active' => $active,
3445
':name' => $name,
3446
':quota_b' => $quota_b,
3447
':attribute_hash' => $attribute_hash,
3448
':force_pw_update' => $force_pw_update,
3449
':force_tfa' => $force_tfa,
3450
':sogo_access' => $sogo_access,
3451
':imap_access' => $imap_access,
3452
':pop3_access' => $pop3_access,
3453
':sieve_access' => $sieve_access,
3454
':smtp_access' => $smtp_access,
3455
':eas_access' => $eas_access,
3456
':dav_access' => $dav_access,
3457
':recovery_email' => $pw_recovery_email,
3458
':relayhost' => $relayhost,
3459
':username' => $username,
3460
':authsource' => $authsource
3461
));
3462
}
3463
catch (PDOException $e) {
3464
$_SESSION['return'][] = array(
3465
'type' => 'danger',
3466
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3467
'msg' => $e->getMessage()
3468
);
3469
return false;
3470
}
3471
// save delimiter_action
3472
if (isset($_data['tagged_mail_handler'])) {
3473
mailbox('edit', 'delimiter_action', array(
3474
'username' => $username,
3475
'tagged_mail_handler' => $_data['tagged_mail_handler']
3476
));
3477
}
3478
// save tags
3479
foreach($tags as $index => $tag){
3480
if (empty($tag)) continue;
3481
if ($index > $GLOBALS['TAGGING_LIMIT']) {
3482
$_SESSION['return'][] = array(
3483
'type' => 'warning',
3484
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3485
'msg' => array('tag_limit_exceeded', 'limit '.$GLOBALS['TAGGING_LIMIT'])
3486
);
3487
break;
3488
}
3489
try {
3490
$stmt = $pdo->prepare("INSERT INTO `tags_mailbox` (`username`, `tag_name`) VALUES (:username, :tag_name)");
3491
$stmt->execute(array(
3492
':username' => $username,
3493
':tag_name' => $tag,
3494
));
3495
} catch (Exception $e) {
3496
}
3497
}
3499
$_SESSION['return'][] = array(
3500
'type' => 'success',
3501
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3502
'msg' => array('mailbox_modified', $username)
3503
);
3505
// Track affected mailboxes for SOGo update
3506
$update_sogo_mailboxes[] = $username;
3507
}
3508
break;
3509
case 'mailbox_rename':
3510
$domain = $_data['domain'];
3511
$old_local_part = $_data['old_local_part'];
3512
$old_username = $old_local_part . "@" . $domain;
3513
$new_local_part = $_data['new_local_part'];
3514
$new_username = $new_local_part . "@" . $domain;
3515
$create_alias = intval($_data['create_alias']);
3517
if (!filter_var($old_username, FILTER_VALIDATE_EMAIL)) {
3518
$_SESSION['return'][] = array(
3519
'type' => 'danger',
3520
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3521
'msg' => array('username_invalid', $old_username)
3522
);
3523
return false;
3524
}
3525
if (!filter_var($new_username, FILTER_VALIDATE_EMAIL)) {
3526
$_SESSION['return'][] = array(
3527
'type' => 'danger',
3528
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3529
'msg' => array('username_invalid', $new_username)
3530
);
3531
return false;
3532
}
3534
$is_now = mailbox('get', 'mailbox_details', $old_username);
3535
if (empty($is_now) || ($is_now['active'] != '1' && $is_now['active'] != '2')) {
3536
$_SESSION['return'][] = array(
3537
'type' => 'danger',
3538
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3539
'msg' => 'access_denied'
3540
);
3541
return false;
3542
}
3544
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $is_now['domain'])) {
3545
$_SESSION['return'][] = array(
3546
'type' => 'danger',
3547
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3548
'msg' => 'access_denied'
3549
);
3550
return false;
3551
}
3553
// get imap acls
3554
try {
3555
$exec_fields = array(
3556
'cmd' => 'doveadm',
3557
'task' => 'get_acl',
3558
'id' => $old_username
3559
);
3560
$imap_acls = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
3561
// delete imap acls
3562
foreach ($imap_acls as $imap_acl) {
3563
$exec_fields = array(
3564
'cmd' => 'doveadm',
3565
'task' => 'delete_acl',
3566
'user' => $imap_acl['user'],
3567
'mailbox' => $imap_acl['mailbox'],
3568
'id' => $imap_acl['id']
3569
);
3570
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3571
}
3572
} catch (Exception $e) {
3573
$_SESSION['return'][] = array(
3574
'type' => 'danger',
3575
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3576
'msg' => $e->getMessage()
3577
);
3578
return false;
3579
}
3581
// rename username in sql
3582
try {
3583
$pdo->beginTransaction();
3584
$pdo->exec('SET FOREIGN_KEY_CHECKS = 0');
3586
// Update username in mailbox table
3587
$pdo->prepare('UPDATE mailbox SET username = :new_username, local_part = :new_local_part WHERE username = :old_username')
3588
->execute([
3589
':new_username' => $new_username,
3590
':new_local_part' => $new_local_part,
3591
':old_username' => $old_username
3592
]);
3594
$pdo->prepare("UPDATE alias SET address = :new_username, goto = :new_username2 WHERE address = :old_username")
3595
->execute([
3596
':new_username' => $new_username,
3597
':new_username2' => $new_username,
3598
':old_username' => $old_username
3599
]);
3601
// Update the username in all related tables
3602
$tables = [
3603
'tags_mailbox' => ['username'],
3604
'sieve_filters' => ['username'],
3605
'app_passwd' => ['mailbox'],
3606
'user_acl' => ['username'],
3607
'da_acl' => ['username'],
3608
'quota2' => ['username'],
3609
'quota2replica' => ['username'],
3610
'pushover' => ['username'],
3611
'alias' => ['goto'],
3612
"imapsync" => ['user2'],
3613
'bcc_maps' => ['local_dest', 'bcc_dest'],
3614
'recipient_maps' => ['old_dest', 'new_dest'],
3615
'sender_acl' => ['logged_in_as', 'send_as']
3616
];
3617
foreach ($tables as $table => $columns) {
3618
foreach ($columns as $column) {
3619
$stmt = $pdo->prepare("UPDATE $table SET $column = :new_username WHERE $column = :old_username")
3620
->execute([
3621
':new_username' => $new_username,
3622
':old_username' => $old_username
3623
]);
3624
}
3625
}
3627
// Update c_uid, c_name and mail in _sogo_static_view table
3628
$pdo->prepare("UPDATE _sogo_static_view SET c_uid = :new_username, c_name = :new_username2, mail = :new_username3 WHERE c_uid = :old_username")
3629
->execute([
3630
':new_username' => $new_username,
3631
':new_username2' => $new_username,
3632
':new_username3' => $new_username,
3633
':old_username' => $old_username
3634
]);
3636
// Re-enable foreign key checks
3637
$pdo->exec('SET FOREIGN_KEY_CHECKS = 1');
3638
$pdo->commit();
3639
} catch (PDOException $e) {
3640
// Rollback the transaction if something goes wrong
3641
$pdo->rollBack();
3642
$_SESSION['return'][] = array(
3643
'type' => 'danger',
3644
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3645
'msg' => $e->getMessage()
3646
);
3647
return false;
3648
}
3650
// move maildir
3651
$exec_fields = array(
3652
'cmd' => 'maildir',
3653
'task' => 'move',
3654
'old_maildir' => $domain . '/' . $old_local_part,
3655
'new_maildir' => $domain . '/' . $new_local_part
3656
);
3657
if (getenv("CLUSTERMODE") == "replication") {
3658
// broadcast to each dovecot container
3659
docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
3660
} else {
3661
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3662
}
3664
// rename username in sogo
3665
$exec_fields = array(
3666
'cmd' => 'sogo',
3667
'task' => 'rename_user',
3668
'old_username' => $old_username,
3669
'new_username' => $new_username
3670
);
3671
docker('post', 'sogo-mailcow', 'exec', $exec_fields);
3673
// set imap acls
3674
foreach ($imap_acls as $imap_acl) {
3675
$user_id = ($imap_acl['id'] == $old_username) ? $new_username : $imap_acl['id'];
3676
$user = ($imap_acl['user'] == $old_username) ? $new_username : $imap_acl['user'];
3677
$exec_fields = array(
3678
'cmd' => 'doveadm',
3679
'task' => 'set_acl',
3680
'user' => $user,
3681
'mailbox' => $imap_acl['mailbox'],
3682
'id' => $user_id,
3683
'rights' => $imap_acl['rights']
3684
);
3685
docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
3686
}
3688
// create alias
3689
if ($create_alias == 1) {
3690
mailbox("add", "alias", array(
3691
"address" => $old_username,
3692
"goto" => $new_username,
3693
"active" => 1,
3694
"sogo_visible" => 1,
3695
"private_comment" => sprintf($lang['success']['mailbox_renamed'], $old_username, $new_username)
3696
));
3697
}
3699
$_SESSION['return'][] = array(
3700
'type' => 'success',
3701
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3702
'msg' => array('mailbox_renamed', $old_username, $new_username)
3703
);
3704
break;
3705
case 'mailbox_from_template':
3706
$stmt = $pdo->prepare("SELECT * FROM `templates`
3707
WHERE `template` = :template AND type = 'mailbox'");
3708
$stmt->execute(array(
3709
":template" => $_data['template']
3710
));
3711
$mbox_template_data = $stmt->fetch(PDO::FETCH_ASSOC);
3712
if (empty($mbox_template_data)){
3713
$_SESSION['return'][] = array(
3714
'type' => 'danger',
3715
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3716
'msg' => 'template_missing'
3717
);
3718
return false;
3719
}
3721
$attribute_hash = sha1(json_encode($mbox_template_data["attributes"]));
3722
$is_now = mailbox('get', 'mailbox_details', $_data['username']);
3723
$name = ltrim(rtrim($_data['name'], '>'), '<');
3724
if ($is_now['attributes']['attribute_hash'] == $attribute_hash && $is_now['name'] == $name)
3725
return true;
3727
$mbox_template_data = json_decode($mbox_template_data["attributes"], true);
3728
$mbox_template_data['attribute_hash'] = $attribute_hash;
3729
$mbox_template_data['name'] = $name;
3730
$quarantine_attributes = array('username' => $_data['username']);
3731
$tls_attributes = array('username' => $_data['username']);
3732
$ratelimit_attributes = array('object' => $_data['username']);
3733
$acl_attributes = array('username' => $_data['username'], 'user_acl' => array());
3734
$mailbox_attributes = array('username' => $_data['username']);
3735
foreach ($mbox_template_data as $key => $value){
3736
switch (true) {
3737
case (strpos($key, 'quarantine_') === 0):
3738
$quarantine_attributes[$key] = $value;
3739
break;
3740
case (strpos($key, 'tls_') === 0):
3741
if ($value == null)
3742
$value = 0;
3743
$tls_attributes[$key] = $value;
3744
break;
3745
case (strpos($key, 'rl_') === 0):
3746
$ratelimit_attributes[$key] = $value;
3747
break;
3748
case (strpos($key, 'acl_') === 0 && $value != 0):
3749
array_push($acl_attributes['user_acl'], str_replace('acl_' , '', $key));
3750
break;
3751
default:
3752
$mailbox_attributes[$key] = $value;
3753
break;
3754
}
3755
}
3757
$mailbox_attributes['quota'] = intval($mailbox_attributes['quota'] / 1048576);
3758
$result = mailbox('edit', 'mailbox', $mailbox_attributes);
3759
if ($result === false) return $result;
3760
$result = mailbox('edit', 'tls_policy', $tls_attributes);
3761
if ($result === false) return $result;
3762
$result = mailbox('edit', 'quarantine_notification', $quarantine_attributes);
3763
if ($result === false) return $result;
3764
$result = mailbox('edit', 'quarantine_category', $quarantine_attributes);
3765
if ($result === false) return $result;
3766
$result = ratelimit('edit', 'mailbox', $ratelimit_attributes);
3767
if ($result === false) return $result;
3768
$result = acl('edit', 'user', $acl_attributes);
3769
if ($result === false) return $result;
3771
$_SESSION['return'] = array();
3772
return true;
3773
break;
3774
case 'mailbox_templates':
3775
if ($_SESSION['mailcow_cc_role'] != "admin") {
3776
$_SESSION['return'][] = array(
3777
'type' => 'danger',
3778
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3779
'msg' => 'access_denied'
3780
);
3781
return false;
3782
}
3783
if (!is_array($_data['ids'])) {
3784
$ids = array();
3785
$ids[] = $_data['ids'];
3786
}
3787
else {
3788
$ids = $_data['ids'];
3789
}
3790
foreach ($ids as $id) {
3791
$is_now = mailbox("get", "mailbox_templates", $id);
3792
if (empty($is_now) ||
3793
$is_now["type"] != "mailbox"){
3794
$_SESSION['return'][] = array(
3795
'type' => 'danger',
3796
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3797
'msg' => 'template_id_invalid'
3798
);
3799
continue;
3800
}
3803
// check name
3804
if ($is_now["template"] == "Default" && $is_now["template"] != $_data["template"]){
3805
// keep template name of Default template
3806
$_data["template"] = $is_now["template"];
3807
}
3808
else {
3809
$_data["template"] = (isset($_data["template"])) ? $_data["template"] : $is_now["template"];
3810
}
3811
// check attributes
3812
$attr = array();
3813
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
3814
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
3815
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : $is_now['tagged_mail_handler'];
3816
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
3817
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
3818
// Validate quarantine_category
3819
if (!in_array($attr["quarantine_category"], array('add_header', 'reject', 'all'))) {
3820
$_SESSION['return'][] = array(
3821
'type' => 'danger',
3822
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
3823
'msg' => 'quarantine_category_invalid'
3824
);
3825
continue;
3826
}
3827
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
3828
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
3829
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
3830
$attr["force_tfa"] = isset($_data['force_tfa']) ? intval($_data['force_tfa']) : $is_now['force_tfa'];
3831
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
3832
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
3833
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
3834
$attr["tls_enforce_out"] = isset($_data['tls_enforce_out']) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out'];
3835
if (isset($_data['protocol_access'])) {
3836
$_data['protocol_access'] = (array)$_data['protocol_access'];
3837
$attr['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
3838
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
3839
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
3840
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
3841
$attr['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
3842
$attr['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
3843
}
3844
else {
3845
foreach ($is_now as $key => $value){
3846
$attr[$key] = $is_now[$key];
3847
}
3848
}
3849
if (isset($_data['acl'])) {
3850
$_data['acl'] = (array)$_data['acl'];
3851
$attr['acl_spam_alias'] = (in_array('spam_alias', $_data['acl'])) ? 1 : 0;
3852
$attr['acl_tls_policy'] = (in_array('tls_policy', $_data['acl'])) ? 1 : 0;
3853
$attr['acl_spam_score'] = (in_array('spam_score', $_data['acl'])) ? 1 : 0;
3854
$attr['acl_spam_policy'] = (in_array('spam_policy', $_data['acl'])) ? 1 : 0;
3855
$attr['acl_delimiter_action'] = (in_array('delimiter_action', $_data['acl'])) ? 1 : 0;
3856
$attr['acl_syncjobs'] = (in_array('syncjobs', $_data['acl'])) ? 1 : 0;
3857
$attr['acl_eas_reset'] = (in_array('eas_reset', $_data['acl'])) ? 1 : 0;
3858
$attr['acl_sogo_profile_reset'] = (in_array('sogo_profile_reset', $_data['acl'])) ? 1 : 0;
3859
$attr['acl_pushover'] = (in_array('pushover', $_data['acl'])) ? 1 : 0;
3860
$attr['acl_quarantine'] = (in_array('quarantine', $_data['acl'])) ? 1 : 0;
3861
$attr['acl_quarantine_attachments'] = (in_array('quarantine_attachments', $_data['acl'])) ? 1 : 0;
3862
$attr['acl_quarantine_notification'] = (in_array('quarantine_notification', $_data['acl'])) ? 1 : 0;
3863
$attr['acl_quarantine_category'] = (in_array('quarantine_category', $_data['acl'])) ? 1 : 0;
3864
$attr['acl_app_passwds'] = (in_array('app_passwds', $_data['acl'])) ? 1 : 0;
3865
$attr['acl_pw_reset'] = (in_array('pw_reset', $_data['acl'])) ? 1 : 0;
3866
} else {
3867
foreach ($is_now as $key => $value){
3868
$attr[$key] = $is_now[$key];
3869
}
3870
}
3873
// update template
3874
$stmt = $pdo->prepare("UPDATE `templates`
3875
SET `template` = :template, `attributes` = :attributes
3876
WHERE id = :id");
3877
$stmt->execute(array(
3878
":id" => $id ,
3879
":template" => $_data["template"] ,
3880
":attributes" => json_encode($attr)
3881
));
3882
}
3885
$_SESSION['return'][] = array(
3886
'type' => 'success',
3887
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3888
'msg' => array('template_modified', $_data["template"])
3889
);
3890
return true;
3891
break;
3892
case 'mailbox_custom_attribute':
3893
$_data['attribute'] = isset($_data['attribute']) ? $_data['attribute'] : array();
3894
$_data['attribute'] = is_array($_data['attribute']) ? $_data['attribute'] : array($_data['attribute']);
3895
$_data['attribute'] = array_map(function($value) { return str_replace(' ', '', $value); }, $_data['attribute']);
3896
$_data['value'] = isset($_data['value']) ? $_data['value'] : array();
3897
$_data['value'] = is_array($_data['value']) ? $_data['value'] : array($_data['value']);
3898
$attributes = (object)array_combine($_data['attribute'], $_data['value']);
3899
$mailboxes = is_array($_data['mailboxes']) ? $_data['mailboxes'] : array($_data['mailboxes']);
3901
foreach ($mailboxes as $mailbox) {
3902
if (!filter_var($mailbox, FILTER_VALIDATE_EMAIL)) {
3903
$_SESSION['return'][] = array(
3904
'type' => 'danger',
3905
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3906
'msg' => array('username_invalid', $mailbox)
3907
);
3908
continue;
3909
}
3910
$is_now = mailbox('get', 'mailbox_details', $mailbox);
3911
if(!empty($is_now)){
3912
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $is_now['domain'])) {
3913
$_SESSION['return'][] = array(
3914
'type' => 'danger',
3915
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3916
'msg' => 'access_denied'
3917
);
3918
continue;
3919
}
3920
}
3921
else {
3922
$_SESSION['return'][] = array(
3923
'type' => 'danger',
3924
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3925
'msg' => 'access_denied'
3926
);
3927
continue;
3928
}
3931
$stmt = $pdo->prepare("UPDATE `mailbox`
3932
SET `custom_attributes` = :custom_attributes
3933
WHERE username = :username");
3934
$stmt->execute(array(
3935
":username" => $mailbox,
3936
":custom_attributes" => json_encode($attributes)
3937
));
3939
$_SESSION['return'][] = array(
3940
'type' => 'success',
3941
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3942
'msg' => array('mailbox_modified', $mailbox)
3943
);
3944
}
3946
return true;
3947
break;
3948
case 'mta_sts':
3949
if (!is_array($_data['domains'])) {
3950
$domains = array();
3951
$domains[] = $_data['domains'];
3952
}
3953
else {
3954
$domains = $_data['domains'];
3955
}
3957
foreach ($domains as $domain) {
3958
$domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
3960
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
3961
$_SESSION['return'][] = array(
3962
'type' => 'danger',
3963
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
3964
'msg' => 'access_denied'
3965
);
3966
continue;
3967
}
3969
$is_now = mailbox('get', 'mta_sts', $domain);
3970
if (!empty($is_now)) {
3971
$version = (isset($_data['version'])) ? strtolower($_data['version']) : $is_now['version'];
3972
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
3973
$active = ($active == 1) ? 1 : 0;
3974
$mode = (isset($_data['mode'])) ? strtolower($_data['mode']) : $is_now['mode'];
3975
$mx = (isset($_data['mx'])) ? explode(",", preg_replace('/\s+/', '', $_data['mx'])) : $is_now['mx'];
3976
$max_age = (isset($_data['max_age'])) ? intval($_data['max_age']) : $is_now['max_age'];
3978
// Update ID if neccesary
3979
if ($version != strtolower($is_now['version']) ||
3980
$mode != strtolower($is_now['mode']) ||
3981
$mx != $is_now['mx'] ||
3982
$max_age != $is_now['max_age']) {
3983
$id = date('YmdHis');
3984
} else {
3985
$id = $is_now['id'];
3986
}
3988
} else {
3989
$_SESSION['return'][] = array(
3990
'type' => 'danger',
3991
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
3992
'msg' => 'access_denied'
3993
);
3994
continue;
3995
}
3997
if (empty($version) || !in_array($version, array('stsv1'))) {
3998
$_SESSION['return'][] = array(
3999
'type' => 'danger',
4000
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
4001
'msg' => array('version_invalid', htmlspecialchars($version))
4002
);
4003
continue;
4004
}
4005
if (empty($mode) || !in_array($mode, array('enforce', 'testing', 'none'))) {
4006
$_SESSION['return'][] = array(
4007
'type' => 'danger',
4008
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
4009
'msg' => array('mode_invalid', htmlspecialchars($domain))
4010
);
4011
continue;
4012
}
4013
if (empty($max_age) || $max_age < 0 || $max_age > 31557600) {
4014
$_SESSION['return'][] = array(
4015
'type' => 'danger',
4016
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
4017
'msg' => array('max_age_invalid', htmlspecialchars($domain))
4018
);
4019
continue;
4020
}
4021
foreach ($mx as $index => $mx_domain) {
4022
$mx_domain = idn_to_ascii(strtolower(trim($mx_domain)), 0, INTL_IDNA_VARIANT_UTS46);
4023
$invalid_mx = false;
4024
if (!is_valid_domain_name($mx_domain, array('allow_wildcard' => true))) {
4025
$invalid_mx = $mx_domain;
4026
break;
4027
}
4028
}
4029
if ($invalid_mx) {
4030
$_SESSION['return'][] = array(
4031
'type' => 'danger',
4032
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
4033
'msg' => array('mx_invalid', htmlspecialchars($invalid_mx))
4034
);
4035
continue;
4036
}
4038
try {
4039
$stmt = $pdo->prepare("UPDATE `mta_sts` SET `id` = :id, `version` = :version, `mode` = :mode, `mx` = :mx, `max_age` = :max_age, `active` = :active WHERE `domain` = :domain");
4040
$stmt->execute(array(
4041
':id' => $id,
4042
':domain' => $domain,
4043
':version' => $version,
4044
':mode' => $mode,
4045
':mx' => implode(",", $mx),
4046
':max_age' => $max_age,
4047
':active' => $active
4048
));
4049
} catch (PDOException $e) {
4050
$_SESSION['return'][] = array(
4051
'type' => 'danger',
4052
'log' => array(__FUNCTION__, $_action, $_type, $_data),
4053
'msg' => $e->getMessage()
4054
);
4055
continue;
4056
}
4058
$_SESSION['return'][] = array(
4059
'type' => 'success',
4060
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
4061
'msg' => array('object_modified', $domain)
4062
);
4063
}
4065
return true;
4066
break;
4067
case 'resource':
4068
if (!is_array($_data['name'])) {
4069
$names = array();
4070
$names[] = $_data['name'];
4071
}
4072
else {
4073
$names = $_data['name'];
4074
}
4075
foreach ($names as $name) {
4076
$is_now = mailbox('get', 'resource_details', $name);
4077
if (!empty($is_now)) {
4078
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
4079
$multiple_bookings = (isset($_data['multiple_bookings'])) ? intval($_data['multiple_bookings']) : $is_now['multiple_bookings'];
4080
$description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
4081
$kind = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind'];
4082
}
4083
else {
4084
$_SESSION['return'][] = array(
4085
'type' => 'danger',
4086
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4087
'msg' => array('resource_invalid', htmlspecialchars($name))
4088
);
4089
continue;
4090
}
4091
if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
4092
$_SESSION['return'][] = array(
4093
'type' => 'danger',
4094
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4095
'msg' => array('resource_invalid', htmlspecialchars($name))
4096
);
4097
continue;
4098
}
4099
if (!isset($multiple_bookings) || $multiple_bookings < -1) {
4100
$multiple_bookings = -1;
4101
}
4102
if (empty($description)) {
4103
$_SESSION['return'][] = array(
4104
'type' => 'danger',
4105
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4106
'msg' => array('description_invalid', htmlspecialchars($name))
4107
);
4108
continue;
4109
}
4110
if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
4111
$_SESSION['return'][] = array(
4112
'type' => 'danger',
4113
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4114
'msg' => array('resource_invalid', htmlspecialchars($name))
4115
);
4116
continue;
4117
}
4118
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
4119
$_SESSION['return'][] = array(
4120
'type' => 'danger',
4121
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4122
'msg' => 'access_denied'
4123
);
4124
continue;
4125
}
4126
$stmt = $pdo->prepare("UPDATE `mailbox` SET
4127
`active` = :active,
4128
`name`= :description,
4129
`kind`= :kind,
4130
`multiple_bookings`= :multiple_bookings
4131
WHERE `username` = :name");
4132
$stmt->execute(array(
4133
':active' => $active,
4134
':description' => $description,
4135
':multiple_bookings' => $multiple_bookings,
4136
':kind' => $kind,
4137
':name' => $name
4138
));
4139
$_SESSION['return'][] = array(
4140
'type' => 'success',
4141
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4142
'msg' => array('resource_modified', htmlspecialchars($name))
4143
);
4145
// Track affected mailboxes for SOGo update
4146
$update_sogo_mailboxes[] = $name;
4147
}
4148
break;
4149
case 'domain_wide_footer':
4150
if (!is_array($_data['domains'])) {
4151
$domains = array();
4152
$domains[] = $_data['domains'];
4153
}
4154
else {
4155
$domains = $_data['domains'];
4156
}
4158
$footers = array();
4159
$footers['html'] = isset($_data['html']) ? $_data['html'] : '';
4160
$footers['plain'] = isset($_data['plain']) ? $_data['plain'] : '';
4161
$footers['skip_replies'] = isset($_data['skip_replies']) ? (int)$_data['skip_replies'] : 0;
4162
$footers['mbox_exclude'] = array();
4163
$footers['alias_domain_exclude'] = array();
4164
if (isset($_data["exclude"])){
4165
if (!is_array($_data["exclude"])) {
4166
$_data["exclude"] = array($_data["exclude"]);
4167
}
4168
foreach ($_data["exclude"] as $exclude) {
4169
if (filter_var($exclude, FILTER_VALIDATE_EMAIL)) {
4170
$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `address` = :address
4171
UNION
4172
SELECT `username` FROM `mailbox` WHERE `username` = :username");
4173
$stmt->execute(array(
4174
':address' => $exclude,
4175
':username' => $exclude,
4176
));
4177
$row = $stmt->fetch(PDO::FETCH_ASSOC);
4178
if(!$row){
4179
$_SESSION['return'][] = array(
4180
'type' => 'danger',
4181
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4182
'msg' => array('username_invalid', $exclude)
4183
);
4184
continue;
4185
}
4186
array_push($footers['mbox_exclude'], $exclude);
4187
}
4188
elseif (is_valid_domain_name($exclude)) {
4189
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
4190
$stmt->execute(array(
4191
':alias_domain' => $exclude,
4192
));
4193
$row = $stmt->fetch(PDO::FETCH_ASSOC);
4194
if(!$row){
4195
$_SESSION['return'][] = array(
4196
'type' => 'danger',
4197
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4198
'msg' => array('username_invalid', $exclude)
4199
);
4200
continue;
4201
}
4202
array_push($footers['alias_domain_exclude'], $exclude);
4203
}
4204
else {
4205
$_SESSION['return'][] = array(
4206
'type' => 'danger',
4207
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4208
'msg' => array('username_invalid', $exclude)
4209
);
4210
}
4211
}
4212
}
4213
foreach ($domains as $domain) {
4214
$domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
4215
if (!is_valid_domain_name($domain)) {
4216
$_SESSION['return'][] = array(
4217
'type' => 'danger',
4218
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4219
'msg' => 'domain_invalid'
4220
);
4221
return false;
4222
}
4223
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4224
$_SESSION['return'][] = array(
4225
'type' => 'danger',
4226
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4227
'msg' => 'access_denied'
4228
);
4229
return false;
4230
}
4232
try {
4233
$stmt = $pdo->prepare("DELETE FROM `domain_wide_footer` WHERE `domain`= :domain");
4234
$stmt->execute(array(':domain' => $domain));
4235
$stmt = $pdo->prepare("INSERT INTO `domain_wide_footer` (`domain`, `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies`) VALUES (:domain, :html, :plain, :mbox_exclude, :alias_domain_exclude, :skip_replies)");
4236
$stmt->execute(array(
4237
':domain' => $domain,
4238
':html' => $footers['html'],
4239
':plain' => $footers['plain'],
4240
':mbox_exclude' => json_encode($footers['mbox_exclude']),
4241
':alias_domain_exclude' => json_encode($footers['alias_domain_exclude']),
4242
':skip_replies' => $footers['skip_replies'],
4243
));
4244
}
4245
catch (PDOException $e) {
4246
$_SESSION['return'][] = array(
4247
'type' => 'danger',
4248
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4249
'msg' => $e->getMessage()
4250
);
4251
return false;
4252
}
4253
$_SESSION['return'][] = array(
4254
'type' => 'success',
4255
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4256
'msg' => array('domain_footer_modified', htmlspecialchars($domain))
4257
);
4258
}
4259
break;
4260
}
4261
break;
4262
case 'get':
4263
switch ($_type) {
4264
case 'sender_acl_handles':
4265
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4266
return false;
4267
}
4268
$data['sender_acl_domains']['ro'] = array();
4269
$data['sender_acl_domains']['rw'] = array();
4270
$data['sender_acl_domains']['selectable'] = array();
4271
$data['sender_acl_addresses']['ro'] = array();
4272
$data['sender_acl_addresses']['rw'] = array();
4273
$data['sender_acl_addresses']['selectable'] = array();
4274
$data['fixed_sender_aliases'] = array();
4275
$data['fixed_sender_aliases_allowed'] = array();
4276
$data['fixed_sender_aliases_blocked'] = array();
4277
$data['external_sender_aliases'] = array();
4278
// Fixed addresses - split by sender_allowed status
4279
$stmt = $pdo->prepare("SELECT `address`, `sender_allowed` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
4280
$stmt->execute(array(':goto' => '(^|,)'.preg_quote($_data, '/').'($|,)'));
4281
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4282
while ($row = array_shift($rows)) {
4283
// Keep old array for backward compatibility
4284
$data['fixed_sender_aliases'][] = $row['address'];
4285
// Split into allowed/blocked for proper display
4286
if ($row['sender_allowed'] == '1') {
4287
$data['fixed_sender_aliases_allowed'][] = $row['address'];
4288
} else {
4289
$data['fixed_sender_aliases_blocked'][] = $row['address'];
4290
}
4291
}
4292
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias_domain_alias` FROM `mailbox`, `alias_domain`
4293
WHERE `alias_domain`.`target_domain` = `mailbox`.`domain`
4294
AND `mailbox`.`username` = :username");
4295
$stmt->execute(array(':username' => $_data));
4296
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4297
while ($row = array_shift($rows)) {
4298
if (!empty($row['alias_domain_alias'])) {
4299
$data['fixed_sender_aliases'][] = $row['alias_domain_alias'];
4300
}
4301
}
4302
// External addresses
4303
$stmt = $pdo->prepare("SELECT `send_as` as `send_as_external` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `external` = '1'");
4304
$stmt->execute(array(':logged_in_as' => $_data));
4305
$exernal_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4306
while ($row = array_shift($exernal_rows)) {
4307
if (!empty($row['send_as_external'])) {
4308
$data['external_sender_aliases'][] = $row['send_as_external'];
4309
}
4310
}
4311
// Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects
4312
// Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted)
4313
$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` = '*')");
4314
$stmt->execute(array(':logged_in_as' => $_data));
4315
$domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4316
while ($domain_row = array_shift($domain_rows)) {
4317
if (is_valid_domain_name($domain_row['send_as']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
4318
$data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
4319
continue;
4320
}
4321
if (is_valid_domain_name($domain_row['send_as']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
4322
$data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
4323
continue;
4324
}
4325
if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] != 'admin') {
4326
$data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
4327
}
4328
if ($domain_row['send_as'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
4329
$data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
4330
}
4331
}
4332
$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` != '*')");
4333
$stmt->execute(array(':logged_in_as' => $_data));
4334
$address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4335
while ($address_row = array_shift($address_rows)) {
4336
if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
4337
$data['sender_acl_addresses']['ro'][] = $address_row['send_as'];
4338
continue;
4339
}
4340
if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
4341
$data['sender_acl_addresses']['rw'][] = $address_row['send_as'];
4342
continue;
4343
}
4344
}
4345
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
4346
WHERE `domain` NOT IN (
4347
SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl`
4348
WHERE `logged_in_as` = :logged_in_as1
4349
AND `external` = '0'
4350
AND `send_as` LIKE '@%')
4351
UNION
4352
SELECT '*' FROM `domain`
4353
WHERE '*' NOT IN (
4354
SELECT `send_as` FROM `sender_acl`
4355
WHERE `logged_in_as` = :logged_in_as2
4356
AND `external` = '0'
4357
)");
4358
$stmt->execute(array(
4359
':logged_in_as1' => $_data,
4360
':logged_in_as2' => $_data
4361
));
4362
$rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
4363
while ($row_domain = array_shift($rows_domain)) {
4364
if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) {
4365
$data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
4366
continue;
4367
}
4368
if ($row_domain['domain'] == '*' && $_SESSION['mailcow_cc_role'] == 'admin') {
4369
$data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
4370
continue;
4371
}
4372
}
4373
$stmt = $pdo->prepare("SELECT `address` FROM `alias`
4374
WHERE `goto` != :goto
4375
AND `address` NOT IN (
4376
SELECT `send_as` FROM `sender_acl`
4377
WHERE `logged_in_as` = :logged_in_as
4378
AND `external` = '0'
4379
AND `send_as` NOT LIKE '@%')");
4380
$stmt->execute(array(
4381
':logged_in_as' => $_data,
4382
':goto' => $_data
4383
));
4384
$rows_mbox = $stmt->fetchAll(PDO::FETCH_ASSOC);
4385
while ($row = array_shift($rows_mbox)) {
4386
// Aliases are not selectable
4387
if (in_array($row['address'], $data['fixed_sender_aliases'])) {
4388
continue;
4389
}
4390
if (filter_var($row['address'], FILTER_VALIDATE_EMAIL) && hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['address'])) {
4391
$data['sender_acl_addresses']['selectable'][] = $row['address'];
4392
}
4393
}
4394
return $data;
4395
break;
4396
case 'mailboxes':
4397
$mailboxes = array();
4398
if (isset($_extra) && is_array($_extra) && isset($_data)) {
4399
// get by domain and tags
4400
$tags = is_array($_extra) ? $_extra : array();
4402
$sql = "";
4403
foreach ($tags as $key => $tag) {
4404
$sql = $sql."SELECT DISTINCT `username` FROM `tags_mailbox` WHERE `username` LIKE ? AND `tag_name` LIKE ?"; // distinct, avoid duplicates
4405
if ($key === array_key_last($tags)) break;
4406
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
4407
}
4409
// prepend domain to array
4410
$params = array();
4411
foreach ($tags as $key => $val){
4412
array_push($params, '%'.$_data.'%');
4413
array_push($params, '%'.$val.'%');
4414
}
4415
$stmt = $pdo->prepare($sql);
4416
$stmt->execute($params);
4418
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4419
while($row = array_shift($rows)) {
4420
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], explode('@', $row['username'])[1]))
4421
$mailboxes[] = $row['username'];
4422
}
4423
}
4424
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4425
// get by domain
4426
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain");
4427
$stmt->execute(array(
4428
':domain' => $_data,
4429
));
4430
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4431
while($row = array_shift($rows)) {
4432
$mailboxes[] = $row['username'];
4433
}
4434
}
4435
else {
4436
$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)");
4437
$stmt->execute(array(
4438
':username' => $_SESSION['mailcow_cc_username'],
4439
':role' => $_SESSION['mailcow_cc_role'],
4440
));
4441
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4442
while($row = array_shift($rows)) {
4443
$mailboxes[] = $row['username'];
4444
}
4445
}
4446
return $mailboxes;
4447
break;
4448
case 'tls_policy':
4449
$attrs = array();
4450
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4451
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4452
return false;
4453
}
4454
}
4455
else {
4456
$_data = $_SESSION['mailcow_cc_username'];
4457
}
4458
$stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
4459
$stmt->execute(array(':username' => $_data));
4460
$attrs = $stmt->fetch(PDO::FETCH_ASSOC);
4461
$attrs = json_decode($attrs['attributes'], true);
4462
return array(
4463
'tls_enforce_in' => $attrs['tls_enforce_in'],
4464
'tls_enforce_out' => $attrs['tls_enforce_out']
4465
);
4466
break;
4467
case 'quarantine_notification':
4468
$attrs = array();
4469
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4470
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4471
return false;
4472
}
4473
}
4474
else {
4475
$_data = $_SESSION['mailcow_cc_username'];
4476
}
4477
$stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
4478
$stmt->execute(array(':username' => $_data));
4479
$attrs = $stmt->fetch(PDO::FETCH_ASSOC);
4480
$attrs = json_decode($attrs['attributes'], true);
4481
return $attrs['quarantine_notification'];
4482
break;
4483
case 'quarantine_category':
4484
$attrs = array();
4485
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4486
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4487
return false;
4488
}
4489
}
4490
else {
4491
$_data = $_SESSION['mailcow_cc_username'];
4492
}
4493
$stmt = $pdo->prepare("SELECT `attributes` FROM `mailbox` WHERE `username` = :username");
4494
$stmt->execute(array(':username' => $_data));
4495
$attrs = $stmt->fetch(PDO::FETCH_ASSOC);
4496
$attrs = json_decode($attrs['attributes'], true);
4497
return $attrs['quarantine_category'];
4498
break;
4499
case 'filters':
4500
$filters = array();
4501
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4502
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4503
return false;
4504
}
4505
}
4506
else {
4507
$_data = $_SESSION['mailcow_cc_username'];
4508
}
4509
$stmt = $pdo->prepare("SELECT `id` FROM `sieve_filters` WHERE `username` = :username");
4510
$stmt->execute(array(':username' => $_data));
4511
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4512
while($row = array_shift($rows)) {
4513
$filters[] = $row['id'];
4514
}
4515
return $filters;
4516
break;
4517
case 'global_filter_details':
4518
$global_filters = array();
4519
if ($_SESSION['mailcow_cc_role'] != "admin") {
4520
return false;
4521
}
4522
$global_filters['prefilter'] = file_get_contents('/global_sieve/before');
4523
$global_filters['postfilter'] = file_get_contents('/global_sieve/after');
4524
return $global_filters;
4525
break;
4526
case 'filter_details':
4527
$filter_details = array();
4528
if (!is_numeric($_data)) {
4529
return false;
4530
}
4531
$stmt = $pdo->prepare("SELECT CASE `script_name` WHEN 'active' THEN 1 ELSE 0 END AS `active`,
4532
id,
4533
username,
4534
filter_type,
4535
script_data,
4536
script_desc
4537
FROM `sieve_filters`
4538
WHERE `id` = :id");
4539
$stmt->execute(array(':id' => $_data));
4540
$filter_details = $stmt->fetch(PDO::FETCH_ASSOC);
4541
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $filter_details['username'])) {
4542
return false;
4543
}
4544
return $filter_details;
4545
break;
4546
case 'active_user_sieve':
4547
$filter_details = array();
4548
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4549
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4550
return false;
4551
}
4552
}
4553
else {
4554
$_data = $_SESSION['mailcow_cc_username'];
4555
}
4556
$exec_fields = array(
4557
'cmd' => 'sieve',
4558
'task' => 'list',
4559
'username' => $_data
4560
);
4561
$filters = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
4562
$filters = array_filter(preg_split("/(\r\n|\n|\r)/",$filters));
4563
foreach ($filters as $filter) {
4564
if (preg_match('/.+ ACTIVE/i', $filter)) {
4565
$exec_fields = array(
4566
'cmd' => 'sieve',
4567
'task' => 'print',
4568
'script_name' => substr($filter, 0, -7),
4569
'username' => $_data
4570
);
4571
$script = docker('post', 'dovecot-mailcow', 'exec', $exec_fields);
4572
// Remove first line
4573
return preg_replace('/^.+\n/', '', $script);
4574
}
4575
}
4576
return false;
4577
break;
4578
case 'syncjob_details':
4579
$syncjobdetails = array();
4580
if (!is_numeric($_data)) {
4581
return false;
4582
}
4583
if (isset($_extra) && in_array('no_log', $_extra)) {
4584
$field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("returned_text", "password1")');
4585
$fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
4586
while($field = array_shift($fields)) {
4587
$shown_fields[] = $field['Field'];
4588
}
4589
$stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
4590
`active`
4591
FROM `imapsync` WHERE id = :id");
4592
}
4593
elseif (isset($_extra) && in_array('with_password', $_extra)) {
4594
$stmt = $pdo->prepare("SELECT *,
4595
`active`
4596
FROM `imapsync` WHERE id = :id");
4597
}
4598
else {
4599
$field_query = $pdo->query('SHOW FIELDS FROM `imapsync` WHERE FIELD NOT IN ("password1")');
4600
$fields = $field_query->fetchAll(PDO::FETCH_ASSOC);
4601
while($field = array_shift($fields)) {
4602
$shown_fields[] = $field['Field'];
4603
}
4604
$stmt = $pdo->prepare("SELECT " . implode(',', (array)$shown_fields) . ",
4605
`active`
4606
FROM `imapsync` WHERE id = :id");
4607
}
4608
$stmt->execute(array(':id' => $_data));
4609
$syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
4610
if (!empty($syncjobdetails['returned_text'])) {
4611
$syncjobdetails['log'] = $syncjobdetails['returned_text'];
4612
}
4613
else {
4614
$syncjobdetails['log'] = '';
4615
}
4616
unset($syncjobdetails['returned_text']);
4617
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) {
4618
return false;
4619
}
4620
return $syncjobdetails;
4621
break;
4622
case 'syncjobs':
4623
$syncjobdata = array();
4624
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4625
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4626
return false;
4627
}
4628
}
4629
else {
4630
$_data = $_SESSION['mailcow_cc_username'];
4631
}
4632
$stmt = $pdo->prepare("SELECT `id` FROM `imapsync` WHERE `user2` = :username");
4633
$stmt->execute(array(':username' => $_data));
4634
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4635
while($row = array_shift($rows)) {
4636
$syncjobdata[] = $row['id'];
4637
}
4638
return $syncjobdata;
4639
break;
4640
case 'spam_score':
4641
$curl = curl_init();
4642
curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
4643
curl_setopt($curl, CURLOPT_URL,"http://rspamd/actions");
4644
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
4645
$default_actions = curl_exec($curl);
4646
if (!curl_errno($curl)) {
4647
$data_array = json_decode($default_actions, true);
4648
curl_close($curl);
4649
foreach ($data_array as $data) {
4650
if ($data['action'] == 'reject') {
4651
$reject = $data['value'];
4652
continue;
4653
}
4654
elseif ($data['action'] == 'add header') {
4655
$add_header = $data['value'];
4656
continue;
4657
}
4658
}
4659
if (empty($add_header) || empty($reject)) {
4660
// Assume default, set warning
4661
$default = "5, 15";
4662
$_SESSION['return'][] = array(
4663
'type' => 'warning',
4664
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4665
'msg' => 'Could not determine servers default spam score, assuming default'
4666
);
4667
}
4668
else {
4669
$default = $add_header . ', ' . $reject;
4670
}
4671
}
4672
else {
4673
// Assume default, set warning
4674
$default = "5, 15";
4675
$_SESSION['return'][] = array(
4676
'type' => 'warning',
4677
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4678
'msg' => 'Could not determine servers default spam score, assuming default'
4679
);
4680
}
4681
curl_close($curl);
4682
$policydata = array();
4683
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4684
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4685
return false;
4686
}
4687
}
4688
else {
4689
$_data = $_SESSION['mailcow_cc_username'];
4690
}
4691
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
4692
(`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
4693
$stmt->execute(array(':username' => $_data));
4694
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
4695
if (empty($num_results)) {
4696
return $default;
4697
}
4698
else {
4699
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'highspamlevel' AND `object` = :username");
4700
$stmt->execute(array(':username' => $_data));
4701
$highspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
4702
$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'lowspamlevel' AND `object` = :username");
4703
$stmt->execute(array(':username' => $_data));
4704
$lowspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
4705
return $lowspamlevel['value'].', '.$highspamlevel['value'];
4706
}
4707
break;
4708
case 'time_limited_aliases':
4709
$tladata = array();
4710
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4711
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4712
return false;
4713
}
4714
}
4715
else {
4716
$_data = $_SESSION['mailcow_cc_username'];
4717
}
4718
$stmt = $pdo->prepare("SELECT `address`,
4719
`goto`,
4720
`description`,
4721
`validity`,
4722
`created`,
4723
`modified`,
4724
`permanent`
4725
FROM `spamalias`
4726
WHERE `goto` = :username
4727
AND (`validity` >= :unixnow
4728
OR `permanent` != 0)");
4729
$stmt->execute(array(':username' => $_data, ':unixnow' => time()));
4730
$tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
4731
return $tladata;
4732
break;
4733
case 'delimiter_action':
4734
$policydata = array();
4735
if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
4736
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4737
return false;
4738
}
4739
}
4740
else {
4741
$_data = $_SESSION['mailcow_cc_username'];
4742
}
4743
try {
4744
if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
4745
return "subject";
4746
}
4747
elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
4748
return "subfolder";
4749
}
4750
else {
4751
return "none";
4752
}
4753
}
4754
catch (RedisException $e) {
4755
$_SESSION['return'][] = array(
4756
'type' => 'danger',
4757
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
4758
'msg' => array('redis_error', $e)
4759
);
4760
return false;
4761
}
4762
break;
4763
case 'resources':
4764
$resources = array();
4765
if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4766
return false;
4767
}
4768
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4769
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` = :domain");
4770
$stmt->execute(array(
4771
':domain' => $_data,
4772
));
4773
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4774
while($row = array_shift($rows)) {
4775
$resources[] = $row['username'];
4776
}
4777
}
4778
else {
4779
$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");
4780
$stmt->execute(array(
4781
':username' => $_SESSION['mailcow_cc_username'],
4782
':role' => $_SESSION['mailcow_cc_role'],
4783
));
4784
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4785
while($row = array_shift($rows)) {
4786
$resources[] = $row['username'];
4787
}
4788
}
4789
return $resources;
4790
break;
4791
case 'alias_domains':
4792
$aliasdomains = array();
4793
if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4794
return false;
4795
}
4796
elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4797
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain");
4798
$stmt->execute(array(
4799
':domain' => $_data,
4800
));
4801
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4802
while($row = array_shift($rows)) {
4803
$aliasdomains[] = $row['alias_domain'];
4804
}
4805
}
4806
else {
4807
$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");
4808
$stmt->execute(array(
4809
':username' => $_SESSION['mailcow_cc_username'],
4810
':role' => $_SESSION['mailcow_cc_role'],
4811
));
4812
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4813
while($row = array_shift($rows)) {
4814
$aliasdomains[] = $row['alias_domain'];
4815
}
4816
}
4817
return $aliasdomains;
4818
break;
4819
case 'aliases':
4820
$aliases = array();
4821
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
4822
return false;
4823
}
4824
$stmt = $pdo->prepare("SELECT `id`, `address` FROM `alias` WHERE `address` != `goto` AND `domain` = :domain");
4825
$stmt->execute(array(
4826
':domain' => $_data,
4827
));
4828
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4829
while($row = array_shift($rows)) {
4830
if ($_extra == "address"){
4831
$aliases[] = $row['address'];
4832
} else {
4833
$aliases[] = $row['id'];
4834
}
4835
}
4836
return $aliases;
4837
break;
4838
case 'alias_details':
4839
$aliasdata = array();
4840
$stmt = $pdo->prepare("SELECT
4841
`id`,
4842
`domain`,
4843
`goto`,
4844
`address`,
4845
`public_comment`,
4846
`private_comment`,
4847
`internal`,
4848
`active`,
4849
`sogo_visible`,
4850
`sender_allowed`,
4851
`created`,
4852
`modified`
4853
FROM `alias`
4854
WHERE (`id` = :id OR `address` = :address) AND `address` != `goto`");
4855
$stmt->execute(array(
4856
':id' => $_data,
4857
':address' => $_data,
4858
));
4859
$row = $stmt->fetch(PDO::FETCH_ASSOC);
4860
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
4861
$stmt->execute(array(
4862
':domain' => $row['domain'],
4863
));
4864
$row_alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
4865
if (isset($row_alias_domain['target_domain']) && !empty($row_alias_domain['target_domain'])) {
4866
$aliasdata['in_primary_domain'] = $row_alias_domain['target_domain'];
4867
}
4868
else {
4869
$aliasdata['in_primary_domain'] = "";
4870
}
4871
$aliasdata['id'] = $row['id'];
4872
$aliasdata['domain'] = $row['domain'];
4873
$aliasdata['public_comment'] = $row['public_comment'];
4874
$aliasdata['private_comment'] = $row['private_comment'];
4875
$aliasdata['domain'] = $row['domain'];
4876
$aliasdata['goto'] = $row['goto'];
4877
$aliasdata['address'] = $row['address'];
4878
(!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
4879
$aliasdata['internal'] = $row['internal'];
4880
$aliasdata['active'] = $row['active'];
4881
$aliasdata['active_int'] = $row['active'];
4882
$aliasdata['sogo_visible'] = $row['sogo_visible'];
4883
$aliasdata['sogo_visible_int'] = $row['sogo_visible'];
4884
$aliasdata['sender_allowed'] = $row['sender_allowed'];
4885
$aliasdata['created'] = $row['created'];
4886
$aliasdata['modified'] = $row['modified'];
4887
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
4888
return false;
4889
}
4890
return $aliasdata;
4891
break;
4892
case 'alias_domain_details':
4893
$aliasdomaindata = array();
4894
$rl = ratelimit('get', 'domain', $_data);
4895
$stmt = $pdo->prepare("SELECT
4896
`alias_domain`,
4897
`target_domain`,
4898
`active`,
4899
`created`,
4900
`modified`
4901
FROM `alias_domain`
4902
WHERE `alias_domain` = :aliasdomain");
4903
$stmt->execute(array(
4904
':aliasdomain' => $_data,
4905
));
4906
$row = $stmt->fetch(PDO::FETCH_ASSOC);
4907
$stmt = $pdo->prepare("SELECT `backupmx` FROM `domain` WHERE `domain` = :target_domain");
4908
$stmt->execute(array(
4909
':target_domain' => $row['target_domain']
4910
));
4911
$row_parent = $stmt->fetch(PDO::FETCH_ASSOC);
4912
$aliasdomaindata['alias_domain'] = $row['alias_domain'];
4913
$aliasdomaindata['parent_is_backupmx'] = $row_parent['backupmx'];
4914
$aliasdomaindata['target_domain'] = $row['target_domain'];
4915
$aliasdomaindata['active'] = $row['active'];
4916
$aliasdomaindata['active_int'] = $row['active'];
4917
$aliasdomaindata['rl'] = $rl;
4918
$aliasdomaindata['created'] = $row['created'];
4919
$aliasdomaindata['modified'] = $row['modified'];
4920
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdomaindata['target_domain'])) {
4921
return false;
4922
}
4923
return $aliasdomaindata;
4924
break;
4925
case 'shared_aliases':
4926
$shared_aliases = array();
4927
$stmt = $pdo->query("SELECT `address` FROM `alias`
4928
WHERE `goto` REGEXP ','
4929
AND `address` NOT LIKE '@%'
4930
AND `goto` != `address`");
4931
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4932
while($row = array_shift($rows)) {
4933
$domain = explode("@", $row['address'])[1];
4934
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4935
$shared_aliases[] = $row['address'];
4936
}
4937
}
4939
return $shared_aliases;
4940
break;
4941
case 'direct_aliases':
4942
$direct_aliases = array();
4943
$stmt = $pdo->query("SELECT `address` FROM `alias`
4944
WHERE `goto` NOT LIKE '%,%'
4945
AND `address` NOT LIKE '@%'
4946
AND `goto` != `address`");
4947
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4949
while($row = array_shift($rows)) {
4950
$domain = explode("@", $row['address'])[1];
4951
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
4952
$direct_aliases[] = $row['address'];
4953
}
4954
}
4956
return $direct_aliases;
4957
break;
4958
case 'domains':
4959
$domains = array();
4960
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
4961
return false;
4962
}
4964
if (isset($_extra) && is_array($_extra)){
4965
// get by tags
4966
$tags = is_array($_extra) ? $_extra : array();
4967
// add % as prefix and suffix to every element for relative searching
4968
$tags = array_map(function($x){ return '%'.$x.'%'; }, $tags);
4969
$sql = "";
4970
foreach ($tags as $key => $tag) {
4971
$sql = $sql."SELECT DISTINCT `domain` FROM `tags_domain` WHERE `tag_name` LIKE ?"; // distinct, avoid duplicates
4972
if ($key === array_key_last($tags)) break;
4973
$sql = $sql.' UNION DISTINCT '; // combine querys with union - distinct, avoid duplicates
4974
}
4975
$stmt = $pdo->prepare($sql);
4976
$stmt->execute($tags);
4978
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4979
while($row = array_shift($rows)) {
4980
if ($_SESSION['mailcow_cc_role'] == "admin")
4981
$domains[] = $row['domain'];
4982
elseif (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain']))
4983
$domains[] = $row['domain'];
4984
}
4985
} else {
4986
// get all
4987
$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
4988
WHERE (`domain` IN (
4989
SELECT `domain` from `domain_admins`
4990
WHERE (`active`='1' AND `username` = :username))
4991
)
4992
OR 'admin'= :role");
4993
$stmt->execute(array(
4994
':username' => $_SESSION['mailcow_cc_username'],
4995
':role' => $_SESSION['mailcow_cc_role'],
4996
));
4997
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
4998
while($row = array_shift($rows)) {
4999
$domains[] = $row['domain'];
5000
}
5001
}
5003
return $domains;
5004
break;
5005
case 'domain_details':
5006
$domaindata = array();
5007
$_data = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
5008
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
5009
return false;
5010
}
5011
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
5012
$stmt->execute(array(
5013
':domain' => $_data
5014
));
5015
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5016
if (!empty($row)) {
5017
$_data = $row['target_domain'];
5018
}
5019
$stmt = $pdo->prepare("SELECT
5020
`domain`,
5021
`description`,
5022
`aliases`,
5023
`mailboxes`,
5024
`defquota`,
5025
`maxquota`,
5026
`created`,
5027
`modified`,
5028
`quota`,
5029
`relayhost`,
5030
`relay_all_recipients`,
5031
`relay_unknown_only`,
5032
`backupmx`,
5033
`gal`,
5034
`active`
5035
FROM `domain` WHERE `domain`= :domain");
5036
$stmt->execute(array(
5037
':domain' => $_data
5038
));
5039
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5040
if (empty($row)) {
5041
return false;
5042
}
5043
$stmt = $pdo->prepare("SELECT COUNT(`username`) AS `count`,
5044
COALESCE(SUM(`quota`), 0) AS `in_use`
5045
FROM `mailbox`
5046
WHERE (`kind` = '' OR `kind` = NULL)
5047
AND `domain` = :domain");
5048
$stmt->execute(array(':domain' => $row['domain']));
5049
$MailboxDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
5050
$stmt = $pdo->prepare("SELECT SUM(bytes) AS `bytes_total`, SUM(messages) AS `msgs_total` FROM `quota2`
5051
WHERE `username` IN (
5052
SELECT `username` FROM `mailbox`
5053
WHERE `domain` = :domain
5054
);");
5055
$stmt->execute(array(':domain' => $row['domain']));
5056
$SumQuotaInUse = $stmt->fetch(PDO::FETCH_ASSOC);
5057
$rl = ratelimit('get', 'domain', $_data);
5058
$domaindata['max_new_mailbox_quota'] = ($row['quota'] * 1048576) - $MailboxDataDomain['in_use'];
5059
if ($domaindata['max_new_mailbox_quota'] > ($row['maxquota'] * 1048576)) {
5060
$domaindata['max_new_mailbox_quota'] = ($row['maxquota'] * 1048576);
5061
}
5062
$domaindata['def_new_mailbox_quota'] = $domaindata['max_new_mailbox_quota'];
5063
if ($domaindata['def_new_mailbox_quota'] > ($row['defquota'] * 1048576)) {
5064
$domaindata['def_new_mailbox_quota'] = ($row['defquota'] * 1048576);
5065
}
5066
$domaindata['quota_used_in_domain'] = $MailboxDataDomain['in_use'];
5067
if (!empty($SumQuotaInUse['bytes_total'])) {
5068
$domaindata['bytes_total'] = $SumQuotaInUse['bytes_total'];
5069
}
5070
else {
5071
$domaindata['bytes_total'] = 0;
5072
}
5073
if (!empty($SumQuotaInUse['msgs_total'])) {
5074
$domaindata['msgs_total'] = $SumQuotaInUse['msgs_total'];
5075
}
5076
else {
5077
$domaindata['msgs_total'] = 0;
5078
}
5079
$domaindata['mboxes_in_domain'] = $MailboxDataDomain['count'];
5080
$domaindata['mboxes_left'] = $row['mailboxes'] - $MailboxDataDomain['count'];
5081
$domaindata['domain_name'] = $row['domain'];
5082
$domaindata['domain_h_name'] = idn_to_utf8($row['domain']);
5083
$domaindata['description'] = $row['description'];
5084
$domaindata['max_num_aliases_for_domain'] = $row['aliases'];
5085
$domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
5086
$domaindata['def_quota_for_mbox'] = $row['defquota'] * 1048576;
5087
$domaindata['max_quota_for_mbox'] = $row['maxquota'] * 1048576;
5088
$domaindata['max_quota_for_domain'] = $row['quota'] * 1048576;
5089
$domaindata['relayhost'] = $row['relayhost'];
5090
$domaindata['backupmx'] = $row['backupmx'];
5091
$domaindata['backupmx_int'] = $row['backupmx'];
5092
$domaindata['gal'] = $row['gal'];
5093
$domaindata['gal_int'] = $row['gal'];
5094
$domaindata['rl'] = $rl;
5095
$domaindata['active'] = $row['active'];
5096
$domaindata['active_int'] = $row['active'];
5097
$domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
5098
$domaindata['relay_all_recipients_int'] = $row['relay_all_recipients'];
5099
$domaindata['relay_unknown_only'] = $row['relay_unknown_only'];
5100
$domaindata['relay_unknown_only_int'] = $row['relay_unknown_only'];
5101
$domaindata['created'] = $row['created'];
5102
$domaindata['modified'] = $row['modified'];
5103
$stmt = $pdo->prepare("SELECT COUNT(`address`) AS `alias_count` FROM `alias`
5104
WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
5105
AND `address` NOT IN (
5106
SELECT `username` FROM `mailbox`
5107
)");
5108
$stmt->execute(array(
5109
':domain' => $_data,
5110
':domain2' => $_data
5111
));
5112
$AliasDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
5113
(isset($AliasDataDomain['alias_count'])) ? $domaindata['aliases_in_domain'] = $AliasDataDomain['alias_count'] : $domaindata['aliases_in_domain'] = "0";
5114
$domaindata['aliases_left'] = $row['aliases'] - $AliasDataDomain['alias_count'];
5115
if ($_SESSION['mailcow_cc_role'] == "admin")
5116
{
5117
$stmt = $pdo->prepare("SELECT GROUP_CONCAT(`username` SEPARATOR ', ') AS domain_admins FROM `domain_admins` WHERE `domain` = :domain");
5118
$stmt->execute(array(
5119
':domain' => $_data
5120
));
5121
$domain_admins = $stmt->fetch(PDO::FETCH_ASSOC);
5122
(isset($domain_admins['domain_admins'])) ? $domaindata['domain_admins'] = $domain_admins['domain_admins'] : $domaindata['domain_admins'] = "-";
5123
}
5124
$stmt = $pdo->prepare("SELECT `tag_name`
5125
FROM `tags_domain` WHERE `domain`= :domain");
5126
$stmt->execute(array(
5127
':domain' => $_data
5128
));
5129
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
5130
while ($tag = array_shift($tags)) {
5131
$domaindata['tags'][] = $tag['tag_name'];
5132
}
5134
return $domaindata;
5135
break;
5136
case 'domain_templates':
5137
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
5138
return false;
5139
}
5140
$_data = (isset($_data)) ? intval($_data) : null;
5142
if (isset($_data)){
5143
$stmt = $pdo->prepare("SELECT * FROM `templates`
5144
WHERE `id` = :id AND type = :type");
5145
$stmt->execute(array(
5146
":id" => $_data,
5147
":type" => "domain"
5148
));
5149
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5151
if (empty($row)){
5152
return false;
5153
}
5155
$row["attributes"] = json_decode($row["attributes"], true);
5156
return $row;
5157
}
5158
else {
5159
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'domain'");
5160
$stmt->execute();
5161
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
5163
if (empty($rows)){
5164
return false;
5165
}
5167
foreach($rows as $key => $row){
5168
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
5169
}
5170
return $rows;
5171
}
5172
break;
5173
case 'mailbox_details':
5174
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
5175
return false;
5176
}
5177
$mailboxdata = array();
5178
if (preg_match('/y|yes/i', getenv('MASTER'))) {
5179
$stmt = $pdo->prepare("SELECT
5180
`domain`.`backupmx`,
5181
`mailbox`.`username`,
5182
`mailbox`.`name`,
5183
`mailbox`.`active`,
5184
`mailbox`.`domain`,
5185
`mailbox`.`local_part`,
5186
`mailbox`.`quota`,
5187
`mailbox`.`created`,
5188
`mailbox`.`modified`,
5189
`mailbox`.`authsource`,
5190
`quota2`.`bytes`,
5191
`attributes`,
5192
`custom_attributes`,
5193
`quota2`.`messages`
5194
FROM `mailbox`, `quota2`, `domain`
5195
WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
5196
AND `mailbox`.`username` = `quota2`.`username`
5197
AND `domain`.`domain` = `mailbox`.`domain`
5198
AND `mailbox`.`username` = :mailbox");
5199
}
5200
else {
5201
$stmt = $pdo->prepare("SELECT
5202
`domain`.`backupmx`,
5203
`mailbox`.`username`,
5204
`mailbox`.`name`,
5205
`mailbox`.`active`,
5206
`mailbox`.`domain`,
5207
`mailbox`.`local_part`,
5208
`mailbox`.`quota`,
5209
`mailbox`.`created`,
5210
`mailbox`.`modified`,
5211
`mailbox`.`authsource`,
5212
`quota2replica`.`bytes`,
5213
`attributes`,
5214
`custom_attributes`,
5215
`quota2replica`.`messages`
5216
FROM `mailbox`, `quota2replica`, `domain`
5217
WHERE (`mailbox`.`kind` = '' OR `mailbox`.`kind` = NULL)
5218
AND `mailbox`.`username` = `quota2replica`.`username`
5219
AND `domain`.`domain` = `mailbox`.`domain`
5220
AND `mailbox`.`username` = :mailbox");
5221
}
5222
$stmt->execute(array(
5223
':mailbox' => $_data,
5224
));
5225
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5227
$mailboxdata['username'] = $row['username'];
5228
$mailboxdata['active'] = $row['active'];
5229
$mailboxdata['active_int'] = $row['active'];
5230
$mailboxdata['domain'] = $row['domain'];
5231
$mailboxdata['name'] = $row['name'];
5232
$mailboxdata['local_part'] = $row['local_part'];
5233
$mailboxdata['quota'] = $row['quota'];
5234
$mailboxdata['messages'] = $row['messages'];
5235
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
5236
$mailboxdata['custom_attributes'] = json_decode($row['custom_attributes'], true);
5237
$mailboxdata['quota_used'] = intval($row['bytes']);
5238
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
5239
$mailboxdata['created'] = $row['created'];
5240
$mailboxdata['modified'] = $row['modified'];
5241
$mailboxdata['authsource'] = ($row['authsource']) ? $row['authsource'] : 'mailcow';
5243
if ($mailboxdata['percent_in_use'] === '- ') {
5244
$mailboxdata['percent_class'] = "info";
5245
}
5246
elseif ($mailboxdata['percent_in_use'] >= 90) {
5247
$mailboxdata['percent_class'] = "danger";
5248
}
5249
elseif ($mailboxdata['percent_in_use'] >= 75) {
5250
$mailboxdata['percent_class'] = "warning";
5251
}
5252
else {
5253
$mailboxdata['percent_class'] = "success";
5254
}
5256
// Determine last logins
5257
$stmt = $pdo->prepare("SELECT MAX(`datetime`) AS `datetime`, `service` FROM `sasl_log`
5258
WHERE `username` = :mailbox
5259
GROUP BY `service` DESC");
5260
$stmt->execute(array(':mailbox' => $_data));
5261
$SaslLogsData = $stmt->fetchAll(PDO::FETCH_ASSOC);
5262
foreach ($SaslLogsData as $SaslLogs) {
5263
if ($SaslLogs['service'] == 'imap') {
5264
$last_imap_login = strtotime($SaslLogs['datetime']);
5265
}
5266
else if ($SaslLogs['service'] == 'smtp') {
5267
$last_smtp_login = strtotime($SaslLogs['datetime']);
5268
}
5269
else if ($SaslLogs['service'] == 'pop3') {
5270
$last_pop3_login = strtotime($SaslLogs['datetime']);
5271
}
5272
else if ($SaslLogs['service'] == 'SSO') {
5273
$last_sso_login = strtotime($SaslLogs['datetime']);
5274
}
5275
}
5276
if (!isset($last_imap_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
5277
$last_imap_login = 0;
5278
}
5279
if (!isset($last_smtp_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
5280
$last_smtp_login = 0;
5281
}
5282
if (!isset($last_pop3_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
5283
$last_pop3_login = 0;
5284
}
5285
if (!isset($last_sso_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
5286
$last_sso_login = 0;
5287
}
5288
$mailboxdata['last_imap_login'] = $last_imap_login;
5289
$mailboxdata['last_smtp_login'] = $last_smtp_login;
5290
$mailboxdata['last_pop3_login'] = $last_pop3_login;
5291
$mailboxdata['last_sso_login'] = $last_sso_login;
5293
if (!isset($_extra) || $_extra != 'reduced') {
5294
$rl = ratelimit('get', 'mailbox', $_data);
5295
$stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
5296
$stmt->execute(array(':domain' => $row['domain']));
5297
$DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
5299
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
5300
$stmt->execute(array(':username' => $_data));
5301
$PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
5302
$stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
5303
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
5304
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
5305
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND (`validity` >= :unixnow OR `permanent` != 0)");
5306
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
5307
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
5308
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
5309
$mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
5310
$mailboxdata['pushover_active'] = ($PushoverActive['pushover_active'] == 1) ? 1 : 0;
5311
if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
5312
$mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
5313
}
5314
if (!empty($rl)) {
5315
$mailboxdata['rl'] = $rl;
5316
$mailboxdata['rl_scope'] = 'mailbox';
5317
}
5318
else {
5319
$mailboxdata['rl'] = ratelimit('get', 'domain', $row['domain']);
5320
$mailboxdata['rl_scope'] = 'domain';
5321
}
5322
$mailboxdata['is_relayed'] = $row['backupmx'];
5323
}
5324
$stmt = $pdo->prepare("SELECT `tag_name`
5325
FROM `tags_mailbox` WHERE `username`= :username");
5326
$stmt->execute(array(
5327
':username' => $_data
5328
));
5329
$tags = $stmt->fetchAll(PDO::FETCH_ASSOC);
5330
while ($tag = array_shift($tags)) {
5331
$mailboxdata['tags'][] = $tag['tag_name'];
5332
}
5334
return $mailboxdata;
5335
break;
5336
case 'mailbox_templates':
5337
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin" && $_SESSION['access_all_exception'] != "1") {
5338
return false;
5339
}
5340
$_data = (isset($_data)) ? intval($_data) : null;
5342
if (isset($_data)){
5343
$stmt = $pdo->prepare("SELECT * FROM `templates`
5344
WHERE `id` = :id AND type = :type");
5345
$stmt->execute(array(
5346
":id" => $_data,
5347
":type" => "mailbox"
5348
));
5349
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5351
if (empty($row)){
5352
return false;
5353
}
5355
$row["attributes"] = json_decode($row["attributes"], true);
5356
return $row;
5357
}
5358
else {
5359
$stmt = $pdo->prepare("SELECT * FROM `templates` WHERE `type` = 'mailbox'");
5360
$stmt->execute();
5361
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
5363
if (empty($rows)){
5364
return false;
5365
}
5367
foreach($rows as $key => $row){
5368
$rows[$key]["attributes"] = json_decode($row["attributes"], true);
5369
}
5370
return $rows;
5371
}
5372
break;
5373
case 'mta_sts':
5374
$stmt = $pdo->prepare("SELECT * FROM `mta_sts` WHERE `domain` = :domain");
5375
$stmt->execute(array(
5376
':domain' => $_data,
5377
));
5378
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5379
if (empty($row)){
5380
return [];
5381
}
5382
$row['mx'] = explode(',', $row['mx']);
5383
$row['version'] = strtoupper(substr($row['version'], 0, 3)) . substr($row['version'], 3);
5385
return $row;
5386
break;
5387
case 'resource_details':
5388
$resourcedata = array();
5389
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
5390
return false;
5391
}
5392
$stmt = $pdo->prepare("SELECT
5393
`username`,
5394
`name`,
5395
`kind`,
5396
`multiple_bookings`,
5397
`local_part`,
5398
`active`,
5399
`domain`
5400
FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
5401
$stmt->execute(array(
5402
':resource' => $_data,
5403
));
5404
$row = $stmt->fetch(PDO::FETCH_ASSOC);
5405
$resourcedata['name'] = $row['username'];
5406
$resourcedata['kind'] = $row['kind'];
5407
$resourcedata['multiple_bookings'] = $row['multiple_bookings'];
5408
$resourcedata['description'] = $row['name'];
5409
$resourcedata['active'] = $row['active'];
5410
$resourcedata['active_int'] = $row['active'];
5411
$resourcedata['domain'] = $row['domain'];
5412
$resourcedata['local_part'] = $row['local_part'];
5413
if (!isset($resourcedata['domain']) ||
5414
(isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
5415
return false;
5416
}
5417
return $resourcedata;
5418
break;
5419
case 'domain_wide_footer':
5420
$domain = idn_to_ascii(strtolower(trim($_data)), 0, INTL_IDNA_VARIANT_UTS46);
5421
if (!is_valid_domain_name($domain)) {
5422
$_SESSION['return'][] = array(
5423
'type' => 'danger',
5424
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5425
'msg' => 'domain_invalid'
5426
);
5427
return false;
5428
}
5429
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
5430
$_SESSION['return'][] = array(
5431
'type' => 'danger',
5432
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5433
'msg' => 'access_denied'
5434
);
5435
return false;
5436
}
5438
try {
5439
$stmt = $pdo->prepare("SELECT `html`, `plain`, `mbox_exclude`, `alias_domain_exclude`, `skip_replies` FROM `domain_wide_footer`
5440
WHERE `domain` = :domain");
5441
$stmt->execute(array(
5442
':domain' => $domain
5443
));
5444
$footer = $stmt->fetch(PDO::FETCH_ASSOC);
5445
}
5446
catch (PDOException $e) {
5447
$_SESSION['return'][] = array(
5448
'type' => 'danger',
5449
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5450
'msg' => $e->getMessage()
5451
);
5452
return false;
5453
}
5455
return $footer;
5456
break;
5457
}
5458
break;
5459
case 'delete':
5460
switch ($_type) {
5461
case 'syncjob':
5462
if (!is_array($_data['id'])) {
5463
$ids = array();
5464
$ids[] = $_data['id'];
5465
}
5466
else {
5467
$ids = $_data['id'];
5468
}
5469
if (!isset($_SESSION['acl']['syncjobs']) || $_SESSION['acl']['syncjobs'] != "1" ) {
5470
$_SESSION['return'][] = array(
5471
'type' => 'danger',
5472
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5473
'msg' => 'access_denied'
5474
);
5475
return false;
5476
}
5477
foreach ($ids as $id) {
5478
if (!is_numeric($id)) {
5479
return false;
5480
}
5481
$stmt = $pdo->prepare("SELECT `user2` FROM `imapsync` WHERE id = :id");
5482
$stmt->execute(array(':id' => $id));
5483
$user2 = $stmt->fetch(PDO::FETCH_ASSOC)['user2'];
5484
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) {
5485
$_SESSION['return'][] = array(
5486
'type' => 'danger',
5487
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5488
'msg' => 'access_denied'
5489
);
5490
continue;
5491
}
5492
$stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `id`= :id");
5493
$stmt->execute(array(':id' => $id));
5494
$_SESSION['return'][] = array(
5495
'type' => 'success',
5496
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5497
'msg' => array('deleted_syncjob', $id)
5498
);
5499
}
5500
break;
5501
case 'filter':
5502
if (!is_array($_data['id'])) {
5503
$ids = array();
5504
$ids[] = $_data['id'];
5505
}
5506
else {
5507
$ids = $_data['id'];
5508
}
5509
if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
5510
$_SESSION['return'][] = array(
5511
'type' => 'danger',
5512
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5513
'msg' => 'access_denied'
5514
);
5515
return false;
5516
}
5517
foreach ($ids as $id) {
5518
if (!is_numeric($id)) {
5519
continue;
5520
}
5521
$stmt = $pdo->prepare("SELECT `username` FROM `sieve_filters` WHERE id = :id");
5522
$stmt->execute(array(':id' => $id));
5523
$usr = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
5524
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $usr)) {
5525
$_SESSION['return'][] = array(
5526
'type' => 'danger',
5527
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5528
'msg' => 'access_denied'
5529
);
5530
continue;
5531
}
5532
$stmt = $pdo->prepare("DELETE FROM `sieve_filters` WHERE `id`= :id");
5533
$stmt->execute(array(':id' => $id));
5534
$_SESSION['return'][] = array(
5535
'type' => 'success',
5536
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5537
'msg' => array('delete_filter', $id)
5538
);
5539
}
5540
break;
5541
case 'time_limited_alias':
5542
if (!is_array($_data['address'])) {
5543
$addresses = array();
5544
$addresses[] = $_data['address'];
5545
}
5546
else {
5547
$addresses = $_data['address'];
5548
}
5549
if (!isset($_SESSION['acl']['spam_alias']) || $_SESSION['acl']['spam_alias'] != "1" ) {
5550
$_SESSION['return'][] = array(
5551
'type' => 'danger',
5552
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5553
'msg' => 'access_denied'
5554
);
5555
return false;
5556
}
5557
foreach ($addresses as $address) {
5558
$stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
5559
$stmt->execute(array(':address' => $address));
5560
$goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
5561
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
5562
$_SESSION['return'][] = array(
5563
'type' => 'danger',
5564
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5565
'msg' => 'access_denied'
5566
);
5567
continue;
5568
}
5569
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username AND `address` = :item");
5570
$stmt->execute(array(
5571
':username' => $goto,
5572
':item' => $address
5573
));
5574
$_SESSION['return'][] = array(
5575
'type' => 'success',
5576
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5577
'msg' => array('mailbox_modified', htmlspecialchars($goto))
5578
);
5579
}
5580
break;
5581
case 'eas_cache':
5582
if (!is_array($_data['username'])) {
5583
$usernames = array();
5584
$usernames[] = $_data['username'];
5585
}
5586
else {
5587
$usernames = $_data['username'];
5588
}
5589
if (!isset($_SESSION['acl']['eas_reset']) || $_SESSION['acl']['eas_reset'] != "1" ) {
5590
$_SESSION['return'][] = array(
5591
'type' => 'danger',
5592
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5593
'msg' => 'access_denied'
5594
);
5595
return false;
5596
}
5597
foreach ($usernames as $username) {
5598
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
5599
$_SESSION['return'][] = array(
5600
'type' => 'danger',
5601
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5602
'msg' => 'access_denied'
5603
);
5604
continue;
5605
}
5606
$stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5607
$stmt->execute(array(
5608
':username' => $username
5609
));
5610
$_SESSION['return'][] = array(
5611
'type' => 'success',
5612
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5613
'msg' => array('eas_reset', htmlspecialchars($username))
5614
);
5615
}
5616
break;
5617
case 'sogo_profile':
5618
if (!is_array($_data['username'])) {
5619
$usernames = array();
5620
$usernames[] = $_data['username'];
5621
}
5622
else {
5623
$usernames = $_data['username'];
5624
}
5625
if (!isset($_SESSION['acl']['sogo_profile_reset']) || $_SESSION['acl']['sogo_profile_reset'] != "1" ) {
5626
$_SESSION['return'][] = array(
5627
'type' => 'danger',
5628
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5629
'msg' => 'access_denied'
5630
);
5631
return false;
5632
}
5633
foreach ($usernames as $username) {
5634
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
5635
$_SESSION['return'][] = array(
5636
'type' => 'danger',
5637
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5638
'msg' => 'access_denied'
5639
);
5640
continue;
5641
}
5642
$stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
5643
$stmt->execute(array(
5644
':username' => $username
5645
));
5646
$stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
5647
$stmt->execute(array(
5648
':username' => $username
5649
));
5650
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
5651
$stmt->execute(array(
5652
':username' => $username
5653
));
5654
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
5655
$stmt->execute(array(
5656
':username' => $username
5657
));
5658
$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)");
5659
$stmt->execute(array(
5660
':username' => $username
5661
));
5662
$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)");
5663
$stmt->execute(array(
5664
':username' => $username
5665
));
5666
$stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
5667
$stmt->execute(array(
5668
':username' => $username
5669
));
5670
$_SESSION['return'][] = array(
5671
'type' => 'success',
5672
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5673
'msg' => array('sogo_profile_reset', htmlspecialchars($username))
5674
);
5675
}
5676
break;
5677
case 'domain':
5678
if (!is_array($_data['domain'])) {
5679
$domains = array();
5680
$domains[] = $_data['domain'];
5681
}
5682
else {
5683
$domains = $_data['domain'];
5684
}
5685
if ($_SESSION['mailcow_cc_role'] != "admin") {
5686
$_SESSION['return'][] = array(
5687
'type' => 'danger',
5688
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5689
'msg' => 'access_denied'
5690
);
5691
return false;
5692
}
5693
foreach ($domains as $domain) {
5694
if (!is_valid_domain_name($domain)) {
5695
$_SESSION['return'][] = array(
5696
'type' => 'danger',
5697
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5698
'msg' => 'domain_invalid'
5699
);
5700
continue;
5701
}
5702
$domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
5703
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
5704
WHERE `domain` = :domain");
5705
$stmt->execute(array(':domain' => $domain));
5706
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
5707
if ($num_results != 0 || !empty($num_results)) {
5708
$_SESSION['return'][] = array(
5709
'type' => 'danger',
5710
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5711
'msg' => array('domain_not_empty', $domain)
5712
);
5713
continue;
5714
}
5715
$exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $domain);
5716
$maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
5717
if ($maildir_gc['type'] != 'success') {
5718
$_SESSION['return'][] = array(
5719
'type' => 'warning',
5720
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5721
'msg' => 'Could not move mail storage to garbage collector: ' . $maildir_gc['msg']
5722
);
5723
}
5724
$stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
5725
$stmt->execute(array(
5726
':domain' => $domain,
5727
));
5728
$stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `domain` = :domain");
5729
$stmt->execute(array(
5730
':domain' => $domain,
5731
));
5732
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :domain");
5733
$stmt->execute(array(
5734
':domain' => $domain,
5735
));
5736
$stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `target_domain` = :domain");
5737
$stmt->execute(array(
5738
':domain' => $domain,
5739
));
5740
$stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `domain` = :domain");
5741
$stmt->execute(array(
5742
':domain' => $domain,
5743
));
5744
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` LIKE :domain");
5745
$stmt->execute(array(
5746
':domain' => '%@'.$domain,
5747
));
5748
$stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain");
5749
$stmt->execute(array(
5750
':domain' => '%@'.$domain,
5751
));
5752
$stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` LIKE :domain");
5753
$stmt->execute(array(
5754
':domain' => '%@'.$domain,
5755
));
5756
$stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` LIKE :domain");
5757
$stmt->execute(array(
5758
':domain' => '%@'.$domain,
5759
));
5760
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
5761
$stmt->execute(array(
5762
':domain' => '%@'.$domain,
5763
));
5764
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
5765
$stmt->execute(array(
5766
':domain' => $domain,
5767
));
5768
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
5769
$stmt->execute(array(
5770
':domain' => $domain,
5771
));
5772
$stmt = $pdo->prepare("DELETE FROM `mta_sts` WHERE `domain` = :domain");
5773
$stmt->execute(array(
5774
':domain' => $domain,
5775
));
5776
$stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
5777
$stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
5778
try {
5779
$redis->hDel('DOMAIN_MAP', $domain);
5780
$redis->hDel('RL_VALUE', $domain);
5781
}
5782
catch (RedisException $e) {
5783
$_SESSION['return'][] = array(
5784
'type' => 'danger',
5785
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5786
'msg' => array('redis_error', $e)
5787
);
5788
continue;
5789
}
5790
$_SESSION['return'][] = array(
5791
'type' => 'success',
5792
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5793
'msg' => array('domain_removed', htmlspecialchars($domain))
5794
);
5795
}
5796
break;
5797
case 'domain_templates':
5798
if ($_SESSION['mailcow_cc_role'] != "admin") {
5799
$_SESSION['return'][] = array(
5800
'type' => 'danger',
5801
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5802
'msg' => 'access_denied'
5803
);
5804
return false;
5805
}
5806
if (!is_array($_data['ids'])) {
5807
$ids = array();
5808
$ids[] = $_data['ids'];
5809
}
5810
else {
5811
$ids = $_data['ids'];
5812
}
5815
foreach ($ids as $id) {
5816
// delete template
5817
$stmt = $pdo->prepare("DELETE FROM `templates`
5818
WHERE id = :id AND type = :type AND NOT template = :template");
5819
$stmt->execute(array(
5820
":id" => $id,
5821
":type" => "domain",
5822
":template" => "Default"
5823
));
5825
$_SESSION['return'][] = array(
5826
'type' => 'success',
5827
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5828
'msg' => array('template_removed', htmlspecialchars($id))
5829
);
5830
return true;
5831
}
5832
break;
5833
case 'alias':
5834
if (!is_array($_data['id'])) {
5835
$ids = array();
5836
$ids[] = $_data['id'];
5837
}
5838
else {
5839
$ids = $_data['id'];
5840
}
5841
foreach ($ids as $id) {
5842
$alias_data = mailbox('get', 'alias_details', $id);
5843
if (empty($alias_data)) {
5844
$_SESSION['return'][] = array(
5845
'type' => 'danger',
5846
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5847
'msg' => 'access_denied'
5848
);
5849
continue;
5850
}
5852
// Track affected mailboxes for SOGo update (capture before deletion)
5853
if (!empty($alias_data['goto'])) {
5854
$gotos = array_map('trim', explode(',', $alias_data['goto']));
5855
foreach ($gotos as $g) {
5856
if (filter_var($g, FILTER_VALIDATE_EMAIL) &&
5857
!in_array($g, array('null@localhost', 'spam@localhost', 'ham@localhost'))) {
5858
$update_sogo_mailboxes[] = $g;
5859
}
5860
}
5861
}
5863
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `id` = :id");
5864
$stmt->execute(array(
5865
':id' => $alias_data['id']
5866
));
5867
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `send_as` = :alias_address");
5868
$stmt->execute(array(
5869
':alias_address' => $alias_data['address']
5870
));
5871
$_SESSION['return'][] = array(
5872
'type' => 'success',
5873
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5874
'msg' => array('alias_removed', htmlspecialchars($alias_data['address']))
5875
);
5876
}
5877
break;
5878
case 'alias_domain':
5879
if (!is_array($_data['alias_domain'])) {
5880
$alias_domains = array();
5881
$alias_domains[] = $_data['alias_domain'];
5882
}
5883
else {
5884
$alias_domains = $_data['alias_domain'];
5885
}
5886
foreach ($alias_domains as $alias_domain) {
5887
if (!is_valid_domain_name($alias_domain)) {
5888
$_SESSION['return'][] = array(
5889
'type' => 'danger',
5890
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5891
'msg' => 'domain_invalid'
5892
);
5893
continue;
5894
}
5895
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
5896
WHERE `alias_domain`= :alias_domain");
5897
$stmt->execute(array(':alias_domain' => $alias_domain));
5898
$DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
5899
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
5900
$_SESSION['return'][] = array(
5901
'type' => 'danger',
5902
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5903
'msg' => 'access_denied'
5904
);
5905
continue;
5906
}
5907
$stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
5908
$stmt->execute(array(
5909
':alias_domain' => $alias_domain,
5910
));
5911
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :alias_domain");
5912
$stmt->execute(array(
5913
':alias_domain' => $alias_domain,
5914
));
5915
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
5916
$stmt->execute(array(
5917
':domain' => '%@'.$alias_domain,
5918
));
5919
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
5920
$stmt->execute(array(
5921
':alias_domain' => $alias_domain,
5922
));
5923
try {
5924
$redis->hDel('DOMAIN_MAP', $alias_domain);
5925
$redis->hDel('RL_VALUE', $domain);
5926
}
5927
catch (RedisException $e) {
5928
$_SESSION['return'][] = array(
5929
'type' => 'danger',
5930
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5931
'msg' => array('redis_error', $e)
5932
);
5933
continue;
5934
}
5935
$_SESSION['return'][] = array(
5936
'type' => 'success',
5937
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5938
'msg' => array('alias_domain_removed', htmlspecialchars($alias_domain))
5939
);
5940
}
5941
break;
5942
case 'mailbox':
5943
if (!is_array($_data['username'])) {
5944
$usernames = array();
5945
$usernames[] = $_data['username'];
5946
}
5947
else {
5948
$usernames = $_data['username'];
5949
}
5950
foreach ($usernames as $username) {
5951
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
5952
$_SESSION['return'][] = array(
5953
'type' => 'danger',
5954
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5955
'msg' => 'access_denied'
5956
);
5957
continue;
5958
}
5959
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
5960
$_SESSION['return'][] = array(
5961
'type' => 'danger',
5962
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5963
'msg' => 'access_denied'
5964
);
5965
continue;
5966
}
5967
$mailbox_details = mailbox('get', 'mailbox_details', $username);
5968
if (!empty($mailbox_details['domain']) && !empty($mailbox_details['local_part'])) {
5969
$maildir = $mailbox_details['domain'] . '/' . $mailbox_details['local_part'];
5970
$exec_fields = array('cmd' => 'maildir', 'task' => 'cleanup', 'maildir' => $maildir);
5972
if (getenv("CLUSTERMODE") == "replication") {
5973
// broadcast to each dovecot container
5974
docker('broadcast', 'dovecot-mailcow', 'exec', $exec_fields);
5975
} else {
5976
$maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
5977
if ($maildir_gc['type'] != 'success') {
5978
$_SESSION['return'][] = array(
5979
'type' => 'warning',
5980
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5981
'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
5982
);
5983
}
5984
}
5985
}
5986
else {
5987
$_SESSION['return'][] = array(
5988
'type' => 'warning',
5989
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
5990
'msg' => 'Could not move maildir to garbage collector: variables local_part and/or domain empty'
5991
);
5992
}
5993
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
5994
$stmt->execute(array(
5995
':username' => $username
5996
));
5997
$stmt = $pdo->prepare("DELETE FROM `pushover` WHERE `username` = :username");
5998
$stmt->execute(array(
5999
':username' => $username
6000
));
6001
$stmt = $pdo->prepare("DELETE FROM `quarantine` WHERE `rcpt` = :username");
6002
$stmt->execute(array(
6003
':username' => $username
6004
));
6005
$stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :username");
6006
$stmt->execute(array(
6007
':username' => $username
6008
));
6009
$stmt = $pdo->prepare("DELETE FROM `quota2replica` WHERE `username` = :username");
6010
$stmt->execute(array(
6011
':username' => $username
6012
));
6013
$stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
6014
$stmt->execute(array(
6015
':username' => $username
6016
));
6017
$stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as OR `send_as` = :send_as");
6018
$stmt->execute(array(
6019
':logged_in_as' => $username,
6020
':send_as' => $username
6021
));
6022
// fk, better safe than sorry
6023
$stmt = $pdo->prepare("DELETE FROM `user_acl` WHERE `username` = :username");
6024
$stmt->execute(array(
6025
':username' => $username
6026
));
6027
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username");
6028
$stmt->execute(array(
6029
':username' => $username
6030
));
6031
$stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `user2` = :username");
6032
$stmt->execute(array(
6033
':username' => $username
6034
));
6035
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username");
6036
$stmt->execute(array(
6037
':username' => $username
6038
));
6039
$stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
6040
$stmt->execute(array(
6041
':username' => $username
6042
));
6043
$stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
6044
$stmt->execute(array(
6045
':username' => $username
6046
));
6047
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
6048
$stmt->execute(array(
6049
':username' => $username
6050
));
6051
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
6052
$stmt->execute(array(
6053
':username' => $username
6054
));
6055
$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)");
6056
$stmt->execute(array(
6057
':username' => $username
6058
));
6059
$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)");
6060
$stmt->execute(array(
6061
':username' => $username
6062
));
6063
$stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
6064
$stmt->execute(array(
6065
':username' => $username
6066
));
6067
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :username");
6068
$stmt->execute(array(
6069
':username' => $username
6070
));
6071
$stmt = $pdo->prepare("DELETE FROM `oauth_access_tokens` WHERE `user_id` = :username");
6072
$stmt->execute(array(
6073
':username' => $username
6074
));
6075
$stmt = $pdo->prepare("DELETE FROM `oauth_refresh_tokens` WHERE `user_id` = :username");
6076
$stmt->execute(array(
6077
':username' => $username
6078
));
6079
$stmt = $pdo->prepare("DELETE FROM `oauth_authorization_codes` WHERE `user_id` = :username");
6080
$stmt->execute(array(
6081
':username' => $username
6082
));
6083
$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
6084
$stmt->execute(array(
6085
':username' => $username,
6086
));
6087
$stmt = $pdo->prepare("DELETE FROM `fido2` WHERE `username` = :username");
6088
$stmt->execute(array(
6089
':username' => $username,
6090
));
6091
$stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
6092
WHERE `goto` REGEXP :username");
6093
$stmt->execute(array(':username' => '(^|,)'.preg_quote($username, '/').'($|,)'));
6094
$GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
6095
foreach ($GotoData as $gotos) {
6096
$goto_exploded = explode(',', $gotos['goto']);
6097
if (($key = array_search($username, $goto_exploded)) !== false) {
6098
unset($goto_exploded[$key]);
6099
}
6100
$gotos_rebuild = implode(',', (array)$goto_exploded);
6101
$stmt = $pdo->prepare("UPDATE `alias` SET
6102
`goto` = :goto
6103
WHERE `address` = :address");
6104
$stmt->execute(array(
6105
':goto' => $gotos_rebuild,
6106
':address' => $gotos['address']
6107
));
6108
}
6109
try {
6110
$redis->hDel('RL_VALUE', $username);
6111
}
6112
catch (RedisException $e) {
6113
$_SESSION['return'][] = array(
6114
'type' => 'danger',
6115
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6116
'msg' => array('redis_error', $e)
6117
);
6118
continue;
6119
}
6121
$_SESSION['return'][] = array(
6122
'type' => 'success',
6123
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6124
'msg' => array('mailbox_removed', htmlspecialchars($username))
6125
);
6127
// Track affected mailboxes for SOGo update
6128
$update_sogo_mailboxes[] = $username;
6129
}
6130
break;
6131
case 'mailbox_templates':
6132
if ($_SESSION['mailcow_cc_role'] != "admin") {
6133
$_SESSION['return'][] = array(
6134
'type' => 'danger',
6135
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6136
'msg' => 'access_denied'
6137
);
6138
return false;
6139
}
6140
if (!is_array($_data['ids'])) {
6141
$ids = array();
6142
$ids[] = $_data['ids'];
6143
}
6144
else {
6145
$ids = $_data['ids'];
6146
}
6149
foreach ($ids as $id) {
6150
// delete template
6151
$stmt = $pdo->prepare("DELETE FROM `templates`
6152
WHERE id = :id AND type = :type AND NOT template = :template");
6153
$stmt->execute(array(
6154
":id" => $id,
6155
":type" => "mailbox",
6156
":template" => "Default"
6157
));
6158
}
6160
$_SESSION['return'][] = array(
6161
'type' => 'success',
6162
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6163
'msg' => 'template_removed'
6164
);
6165
return true;
6166
break;
6167
case 'resource':
6168
if (!is_array($_data['name'])) {
6169
$names = array();
6170
$names[] = $_data['name'];
6171
}
6172
else {
6173
$names = $_data['name'];
6174
}
6175
foreach ($names as $name) {
6176
if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
6177
$_SESSION['return'][] = array(
6178
'type' => 'danger',
6179
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6180
'msg' => 'access_denied'
6181
);
6182
continue;
6183
}
6184
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
6185
$_SESSION['return'][] = array(
6186
'type' => 'danger',
6187
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6188
'msg' => 'access_denied'
6189
);
6190
continue;
6191
}
6192
$stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
6193
$stmt->execute(array(
6194
':username' => $name
6195
));
6196
$stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
6197
$stmt->execute(array(
6198
':username' => $name
6199
));
6200
$stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
6201
$stmt->execute(array(
6202
':username' => $name
6203
));
6204
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
6205
$stmt->execute(array(
6206
':username' => $name
6207
));
6208
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
6209
$stmt->execute(array(
6210
':username' => $name
6211
));
6212
$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)");
6213
$stmt->execute(array(
6214
':username' => $name
6215
));
6216
$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)");
6217
$stmt->execute(array(
6218
':username' => $name
6219
));
6220
$stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
6221
$stmt->execute(array(
6222
':username' => $name
6223
));
6224
$_SESSION['return'][] = array(
6225
'type' => 'success',
6226
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6227
'msg' => array('resource_removed', htmlspecialchars($name))
6228
);
6230
// Track affected mailboxes for SOGo update
6231
$update_sogo_mailboxes[] = $name;
6232
}
6233
break;
6234
case 'tags_domain':
6235
if (!is_array($_data['domain'])) {
6236
$domains = array();
6237
$domains[] = $_data['domain'];
6238
}
6239
else {
6240
$domains = $_data['domain'];
6241
}
6242
$tags = $_data['tags'];
6243
if (!is_array($tags)) $tags = array();
6246
$wasModified = false;
6247
foreach ($domains as $domain) {
6248
if (!is_valid_domain_name($domain)) {
6249
$_SESSION['return'][] = array(
6250
'type' => 'danger',
6251
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6252
'msg' => 'domain_invalid'
6253
);
6254
continue;
6255
}
6256
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
6257
$_SESSION['return'][] = array(
6258
'type' => 'danger',
6259
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6260
'msg' => 'access_denied'
6261
);
6262
return false;
6263
}
6265
foreach($tags as $tag){
6266
// delete tag
6267
$wasModified = true;
6268
$stmt = $pdo->prepare("DELETE FROM `tags_domain` WHERE `domain` = :domain AND `tag_name` = :tag_name");
6269
$stmt->execute(array(
6270
':domain' => $domain,
6271
':tag_name' => $tag,
6272
));
6273
}
6274
}
6276
if (!$wasModified) return false;
6277
$_SESSION['return'][] = array(
6278
'type' => 'success',
6279
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6280
'msg' => array('domain_modified', $domain)
6281
);
6282
break;
6283
case 'tags_mailbox':
6284
if (!is_array($_data['username'])) {
6285
$usernames = array();
6286
$usernames[] = $_data['username'];
6287
}
6288
else {
6289
$usernames = $_data['username'];
6290
}
6291
$tags = $_data['tags'];
6292
if (!is_array($tags)) $tags = array();
6294
$wasModified = false;
6295
foreach ($usernames as $username) {
6296
if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
6297
$_SESSION['return'][] = array(
6298
'type' => 'danger',
6299
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6300
'msg' => 'email invalid'
6301
);
6302
continue;
6303
}
6305
$is_now = mailbox('get', 'mailbox_details', $username);
6306
$domain = $is_now['domain'];
6307
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
6308
$_SESSION['return'][] = array(
6309
'type' => 'danger',
6310
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6311
'msg' => 'access_denied'
6312
);
6313
continue;
6314
}
6316
// delete tags
6317
foreach($tags as $tag){
6318
$wasModified = true;
6320
$stmt = $pdo->prepare("DELETE FROM `tags_mailbox` WHERE `username` = :username AND `tag_name` = :tag_name");
6321
$stmt->execute(array(
6322
':username' => $username,
6323
':tag_name' => $tag,
6324
));
6325
}
6326
}
6328
if (!$wasModified) return false;
6329
$_SESSION['return'][] = array(
6330
'type' => 'success',
6331
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6332
'msg' => array('mailbox_modified', $username)
6333
);
6334
break;
6335
}
6336
break;
6337
}
6338
if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'resource', 'mailbox')) && getenv('SKIP_SOGO') != "y") {
6339
try {
6340
if (($_type == 'alias' || $_type == 'resource' || $_type == 'mailbox') && !empty($update_sogo_mailboxes)) {
6341
// INCREMENTAL UPDATE: Update only affected mailboxes/resources
6342
$update_sogo_mailboxes = array_unique($update_sogo_mailboxes);
6343
foreach ($update_sogo_mailboxes as $mailbox) {
6344
update_sogo_static_view($mailbox);
6345
}
6346
}
6347
else {
6348
// FULL REBUILD: For domain and alias_domain operations or if no tracked mailboxes
6349
// Domain operations affect all mailboxes
6350
// Alias_domain operations affect entire target domain
6351
update_sogo_static_view();
6352
}
6353
}catch (PDOException $e) {
6354
$_SESSION['return'][] = array(
6355
'type' => 'success',
6356
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
6357
'msg' => $e->getMessage()
6358
);
6359
}
6360
}
6362
return true;
6363
}