blob: 140ae47647da6489ce365c6feed4d90e83d5ae0e [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001<?php
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02002function bcc($_action, $_data = null, $_attr = null) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01003 global $pdo;
4 global $lang;
5 if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
6 return false;
7 }
8 switch ($_action) {
9 case 'add':
10 if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
11 $_SESSION['return'][] = array(
12 'type' => 'danger',
13 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
14 'msg' => 'access_denied'
15 );
16 return false;
17 }
18 $local_dest = strtolower(trim($_data['local_dest']));
19 $bcc_dest = $_data['bcc_dest'];
20 $active = intval($_data['active']);
21 $type = $_data['type'];
22 if ($type != 'sender' && $type != 'rcpt') {
23 $_SESSION['return'][] = array(
24 'type' => 'danger',
25 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
26 'msg' => 'invalid_bcc_map_type'
27 );
28 return false;
29 }
30 if (empty($bcc_dest)) {
31 $_SESSION['return'][] = array(
32 'type' => 'danger',
33 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
34 'msg' => 'bcc_empty'
35 );
36 return false;
37 }
38 if (is_valid_domain_name($local_dest)) {
39 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
40 $_SESSION['return'][] = array(
41 'type' => 'danger',
42 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
43 'msg' => 'access_denied'
44 );
45 return false;
46 }
47 $domain = idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
48 $local_dest_sane = '@' . idn_to_ascii($local_dest, 0, INTL_IDNA_VARIANT_UTS46);
49 }
50 elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) {
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020051 $mailbox = mailbox('get', 'mailbox_details', $local_dest);
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +010052 $shared_aliases = mailbox('get', 'shared_aliases');
53 $direct_aliases = mailbox('get', 'direct_aliases');
54 if ($mailbox === false && in_array($local_dest, array_merge($direct_aliases, $shared_aliases)) === false) {
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010055 $_SESSION['return'][] = array(
56 'type' => 'danger',
57 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
58 'msg' => 'access_denied'
59 );
60 return false;
61 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020062 if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest) &&
63 !hasAliasObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
64 $_SESSION['return'][] = array(
65 'type' => 'danger',
66 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
67 'msg' => 'access_denied'
68 );
69 return false;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010070 }
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020071 $domain = idn_to_ascii(substr(strstr($local_dest, '@'), 1), 0, INTL_IDNA_VARIANT_UTS46);
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010072 $local_dest_sane = $local_dest;
73 }
74 else {
75 return false;
76 }
77 if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
78 $_SESSION['return'][] = array(
79 'type' => 'danger',
80 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
81 'msg' => array('bcc_must_be_email', htmlspecialchars($bcc_dest))
82 );
83 return false;
84 }
85
86 $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
87 WHERE `local_dest` = :local_dest AND `type` = :type");
88 $stmt->execute(array(':local_dest' => $local_dest_sane, ':type' => $type));
89 $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
90
91 if ($num_results != 0) {
92 $_SESSION['return'][] = array(
93 'type' => 'danger',
94 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
95 'msg' => array('bcc_exists', htmlspecialchars($local_dest_sane), $type)
96 );
97 return false;
98 }
99 $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
100 (:local_dest, :bcc_dest, :domain, :active, :type)");
101 $stmt->execute(array(
102 ':local_dest' => $local_dest_sane,
103 ':bcc_dest' => $bcc_dest,
104 ':domain' => $domain,
105 ':active' => $active,
106 ':type' => $type
107 ));
108 $_SESSION['return'][] = array(
109 'type' => 'success',
110 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
111 'msg' => 'bcc_saved'
112 );
113 break;
114 case 'edit':
115 if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
116 $_SESSION['return'][] = array(
117 'type' => 'danger',
118 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
119 'msg' => 'access_denied'
120 );
121 return false;
122 }
123 $ids = (array)$_data['id'];
124 foreach ($ids as $id) {
125 $is_now = bcc('details', $id);
126 if (!empty($is_now)) {
127 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
128 $bcc_dest = (!empty($_data['bcc_dest'])) ? $_data['bcc_dest'] : $is_now['bcc_dest'];
129 $local_dest = $is_now['local_dest'];
130 $type = (!empty($_data['type'])) ? $_data['type'] : $is_now['type'];
131 }
132 else {
133 $_SESSION['return'][] = array(
134 'type' => 'danger',
135 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
136 'msg' => 'access_denied'
137 );
138 continue;
139 }
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100140 if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
141 $_SESSION['return'][] = array(
142 'type' => 'danger',
143 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
144 'msg' => array('bcc_must_be_email', $bcc_dest)
145 );
146 continue;
147 }
148 if (empty($bcc_dest)) {
149 $_SESSION['return'][] = array(
150 'type' => 'danger',
151 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
152 'msg' => array('bcc_must_be_email', $bcc_dest)
153 );
154 continue;
155 }
156 $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
157 WHERE `local_dest` = :local_dest AND `type` = :type");
158 $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
159 $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
160
161 if (isset($id_now) && $id_now != $id) {
162 $_SESSION['return'][] = array(
163 'type' => 'danger',
164 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
165 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
166 );
167 continue;
168 }
169
170 $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
171 $stmt->execute(array(
172 ':bcc_dest' => $bcc_dest,
173 ':active' => $active,
174 ':type' => $type,
175 ':id' => $id
176 ));
177 $_SESSION['return'][] = array(
178 'type' => 'success',
179 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
180 'msg' => array('bcc_edited', $bcc_dest)
181 );
182 }
183 break;
184 case 'details':
185 $bccdata = array();
186 $id = intval($_data);
187
188 $stmt = $pdo->prepare("SELECT `id`,
189 `local_dest`,
190 `bcc_dest`,
191 `active`,
192 `type`,
193 `created`,
194 `domain`,
195 `modified` FROM `bcc_maps`
196 WHERE `id` = :id");
197 $stmt->execute(array(':id' => $id));
198 $bccdata = $stmt->fetch(PDO::FETCH_ASSOC);
199
200 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $bccdata['domain'])) {
201 $bccdata = null;
202 return false;
203 }
204 return $bccdata;
205 break;
206 case 'get':
207 $bccdata = array();
208 $all_items = array();
209 $id = intval($_data);
210
211 $stmt = $pdo->query("SELECT `id`, `domain` FROM `bcc_maps`");
212 $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
213
214 foreach ($all_items as $i) {
215 if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $i['domain'])) {
216 $bccdata[] = $i['id'];
217 }
218 }
219 $all_items = null;
220 return $bccdata;
221 break;
222 case 'delete':
223 if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
224 $_SESSION['return'][] = array(
225 'type' => 'danger',
226 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
227 'msg' => 'access_denied'
228 );
229 return false;
230 }
231 $ids = (array)$_data['id'];
232 foreach ($ids as $id) {
233 if (!is_numeric($id)) {
234 return false;
235 }
236 $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
237 $stmt->execute(array(':id' => $id));
238 $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
239 if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
240 $_SESSION['return'][] = array(
241 'type' => 'danger',
242 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
243 'msg' => 'access_denied'
244 );
245 continue;
246 }
247 $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
248 $stmt->execute(array(':id' => $id));
249
250 $_SESSION['return'][] = array(
251 'type' => 'success',
252 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
253 'msg' => array('bcc_deleted', $id)
254 );
255 }
256 break;
257 }
258}
259
260function recipient_map($_action, $_data = null, $attr = null) {
261 global $pdo;
262 global $lang;
263 if ($_SESSION['mailcow_cc_role'] != "admin") {
264 return false;
265 }
266 switch ($_action) {
267 case 'add':
268 $old_dest = strtolower(trim($_data['recipient_map_old']));
269 if (substr($old_dest, 0, 1) == '@') {
270 $old_dest = substr($old_dest, 1);
271 }
272 $new_dest = strtolower(trim($_data['recipient_map_new']));
273 $active = intval($_data['active']);
274 if (is_valid_domain_name($old_dest)) {
275 $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
276 }
277 elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
278 $old_dest_sane = $old_dest;
279 }
280 else {
281 $_SESSION['return'][] = array(
282 'type' => 'danger',
283 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
284 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
285 );
286 return false;
287 }
288 if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
289 $_SESSION['return'][] = array(
290 'type' => 'danger',
291 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
292 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
293 );
294 return false;
295 }
296 $rmaps = recipient_map('get');
297 foreach ($rmaps as $rmap) {
298 if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
299 $_SESSION['return'][] = array(
300 'type' => 'danger',
301 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
302 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
303 );
304 return false;
305 }
306 }
307 $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
308 (:old_dest, :new_dest, :active)");
309 $stmt->execute(array(
310 ':old_dest' => $old_dest_sane,
311 ':new_dest' => $new_dest,
312 ':active' => $active
313 ));
314 $_SESSION['return'][] = array(
315 'type' => 'success',
316 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
317 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
318 );
319 break;
320 case 'edit':
321 $ids = (array)$_data['id'];
322 foreach ($ids as $id) {
323 $is_now = recipient_map('details', $id);
324 if (!empty($is_now)) {
325 $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
326 $new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new'];
327 $old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old'];
328 if (substr($old_dest, 0, 1) == '@') {
329 $old_dest = substr($old_dest, 1);
330 }
331 }
332 else {
333 $_SESSION['return'][] = array(
334 'type' => 'danger',
335 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
336 'msg' => 'access_denied'
337 );
338 continue;
339 }
340 if (is_valid_domain_name($old_dest)) {
341 $old_dest_sane = '@' . idn_to_ascii($old_dest, 0, INTL_IDNA_VARIANT_UTS46);
342 }
343 elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
344 $old_dest_sane = $old_dest;
345 }
346 else {
347 $_SESSION['return'][] = array(
348 'type' => 'danger',
349 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
350 'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
351 );
352 continue;
353 }
354 if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
355 $_SESSION['return'][] = array(
356 'type' => 'danger',
357 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
358 'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
359 );
360 continue;
361 }
362 $rmaps = recipient_map('get');
363 foreach ($rmaps as $rmap) {
364 if ($rmap == $id) { continue; }
365 if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
366 $_SESSION['return'][] = array(
367 'type' => 'danger',
368 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
369 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
370 );
371 return false;
372 }
373 }
374 $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
375 `old_dest` = :old_dest,
376 `new_dest` = :new_dest,
377 `active` = :active
378 WHERE `id`= :id");
379 $stmt->execute(array(
380 ':old_dest' => $old_dest_sane,
381 ':new_dest' => $new_dest,
382 ':active' => $active,
383 ':id' => $id
384 ));
385 $_SESSION['return'][] = array(
386 'type' => 'success',
387 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
388 'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
389 );
390 }
391 break;
392 case 'details':
393 $mapdata = array();
394 $id = intval($_data);
395
396 $stmt = $pdo->prepare("SELECT `id`,
397 `old_dest` AS `recipient_map_old`,
398 `new_dest` AS `recipient_map_new`,
399 `active`,
400 `created`,
401 `modified` FROM `recipient_maps`
402 WHERE `id` = :id");
403 $stmt->execute(array(':id' => $id));
404 $mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
405
406 return $mapdata;
407 break;
408 case 'get':
409 $mapdata = array();
410 $all_items = array();
411 $id = intval($_data);
412
413 $stmt = $pdo->query("SELECT `id` FROM `recipient_maps`");
414 $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
415
416 foreach ($all_items as $i) {
417 $mapdata[] = $i['id'];
418 }
419 $all_items = null;
420 return $mapdata;
421 break;
422 case 'delete':
423 $ids = (array)$_data['id'];
424 foreach ($ids as $id) {
425 if (!is_numeric($id)) {
426 return false;
427 }
428 $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
429 $stmt->execute(array(':id' => $id));
430 $_SESSION['return'][] = array(
431 'type' => 'success',
432 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
433 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($id))
434 );
435 }
436 break;
437 }
438}