From 84ad579437d6e978923b4b82718867fdeb8c9b77 Mon Sep 17 00:00:00 2001 From: andryyy Date: Sun, 16 Jul 2017 11:03:28 +0200 Subject: [PATCH] [Web] Initial ratelimit support, more API actions --- data/web/admin.php | 4 +- data/web/css/edit.css | 3 + data/web/edit.php | 85 ++- data/web/inc/functions.domain_admin.inc.php | 507 +++++++++++++++++ data/web/inc/functions.inc.php | 573 +------------------- data/web/inc/functions.mailbox.inc.php | 134 ++++- data/web/inc/prerequisites.inc.php | 1 + data/web/inc/sessions.inc.php | 2 + data/web/inc/triggers.inc.php | 41 -- data/web/js/api.js | 20 +- data/web/json_api.php | 181 +++++-- data/web/user.php | 4 +- 12 files changed, 855 insertions(+), 700 deletions(-) create mode 100644 data/web/inc/functions.domain_admin.inc.php diff --git a/data/web/admin.php b/data/web/admin.php index 0e0003a8..284bf31b 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -56,7 +56,7 @@ $tfa_data = get_tfa();
- +
@@ -253,7 +253,7 @@ XYZ - +
diff --git a/data/web/css/edit.css b/data/web/css/edit.css index fe4d9fff..07d4e745 100644 --- a/data/web/css/edit.css +++ b/data/web/css/edit.css @@ -27,3 +27,6 @@ table.footable>tbody>tr.footable-empty>td { user-select: none; padding:10px 0 10px 0; } +.inputMissingAttr { + border-color: #FF4136; +} diff --git a/data/web/edit.php b/data/web/edit.php index d156dba0..1f250535 100644 --- a/data/web/edit.php +++ b/data/web/edit.php @@ -25,9 +25,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm ?>


-
"> + -
@@ -43,7 +42,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
- +
@@ -55,20 +54,19 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm


-
"> + -
@@ -122,7 +120,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
- +
@@ -139,14 +137,14 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm !empty($_GET["domain"])) { $domain = $_GET["domain"]; $result = mailbox('get', 'domain_details', $domain); + $rl = mailbox('get', 'domain_ratelimit', $domain); if (!empty($result)) { ?>

-
"> + -
@@ -203,7 +201,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
- +
@@ -223,6 +221,23 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm } ?>
+
+
+ + +
+
+ +
+
+ +
+
+

@@ -282,12 +297,12 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm !empty($_GET["aliasdomain"])) { $alias_domain = $_GET["aliasdomain"]; $result = mailbox('get', 'alias_domain_details', $alias_domain); + $rl = mailbox('get', 'domain_ratelimit', $alias_domain); if (!empty($result)) { ?>

-
"> + -
@@ -303,10 +318,27 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
- +
+
+
+
+ + +
+
+ +
+
+ +
+
@@ -334,10 +366,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm if (!empty($result)) { ?>

-
"> + -
@@ -355,7 +386,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
-
- +
@@ -439,10 +470,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm if (!empty($result)) { ?>

-
"> + -
@@ -475,7 +505,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
- +
@@ -501,11 +531,10 @@ elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == if (!empty($result)) { ?>

-
"> + -
@@ -587,7 +616,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] ==
- +
diff --git a/data/web/inc/functions.domain_admin.inc.php b/data/web/inc/functions.domain_admin.inc.php new file mode 100644 index 00000000..aa434079 --- /dev/null +++ b/data/web/inc/functions.domain_admin.inc.php @@ -0,0 +1,507 @@ + 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + if (empty($domains)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['domain_invalid']) + ); + return false; + } + if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['username_invalid']) + ); + return false; + } + try { + $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` + WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); + + $stmt = $pdo->prepare("SELECT `username` FROM `admin` + WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); + + $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` + WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + foreach ($num_results as $num_results_each) { + if ($num_results_each != 0) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username)) + ); + return false; + } + } + if (!empty($password) && !empty($password2)) { + if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_complexity']) + ); + return false; + } + if ($password != $password2) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_mismatch']) + ); + return false; + } + $password_hashed = hash_password($password); + foreach ($domains as $domain) { + if (!is_valid_domain_name($domain)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['domain_invalid']) + ); + return false; + } + try { + $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) + VALUES (:username, :domain, :created, :active)"); + $stmt->execute(array( + ':username' => $username, + ':domain' => $domain, + ':created' => date('Y-m-d H:i:s'), + ':active' => $active + )); + } + catch (PDOException $e) { + domain_admin('delete', $username); + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + try { + $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`) + VALUES (:username, :password_hashed, '0', :active)"); + $stmt->execute(array( + ':username' => $username, + ':password_hashed' => $password_hashed, + ':active' => $active + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + else { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_empty']) + ); + return false; + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['domain_admin_added'], htmlspecialchars($username)) + ); + break; + case 'edit': + if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + // Administrator + if ($_SESSION['mailcow_cc_role'] == "admin") { + if (!is_array($_data['username'])) { + $usernames = array(); + $usernames[] = $_data['username']; + } + else { + $usernames = $_data['username']; + } + foreach ($usernames as $username) { + $is_now = domain_admin('details', $username); + $domains = (isset($_data['domains'])) ? (array)$_data['domains'] : null; + if (!empty($is_now)) { + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + $domains = (!empty($domains)) ? $domains : $is_now['selected_domains']; + $username_new = (!empty($_data['username_new'])) ? $_data['username_new'] : $is_now['username']; + } + else { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + $password = $_data['password']; + $password2 = $_data['password2']; + + if (!empty($domains)) { + foreach ($domains as $domain) { + if (!is_valid_domain_name($domain)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['domain_invalid']) + ); + return false; + } + } + } + if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['username_invalid']) + ); + return false; + } + if ($username_new != $username) { + if (!empty(domain_admin('details', $username_new)['username'])) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['username_invalid']) + ); + return false; + } + } + try { + $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); + $stmt->execute(array( + ':username' => $username, + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + + if (!empty($domains)) { + foreach ($domains as $domain) { + try { + $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) + VALUES (:username_new, :domain, :created, :active)"); + $stmt->execute(array( + ':username_new' => $username_new, + ':domain' => $domain, + ':created' => date('Y-m-d H:i:s'), + ':active' => $active + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + } + + if (!empty($password) && !empty($password2)) { + if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_complexity']) + ); + return false; + } + if ($password != $password2) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_mismatch']) + ); + return false; + } + $password_hashed = hash_password($password); + try { + $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username"); + $stmt->execute(array( + ':password_hashed' => $password_hashed, + ':username_new' => $username_new, + ':username' => $username, + ':active' => $active + )); + if (isset($_data['disable_tfa'])) { + $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + } + else { + $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); + $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); + } + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + else { + try { + $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username"); + $stmt->execute(array( + ':username_new' => $username_new, + ':username' => $username, + ':active' => $active + )); + if (isset($_data['disable_tfa'])) { + $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); + $stmt->execute(array(':username' => $username)); + } + else { + $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); + $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); + } + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars(implode(', ', $usernames))) + ); + } + // Domain administrator + // Can only edit itself + elseif ($_SESSION['mailcow_cc_role'] == "domainadmin") { + $username = $_SESSION['mailcow_cc_username']; + $password_old = $_data['user_old_pass']; + $password_new = $_data['user_new_pass']; + $password_new2 = $_data['user_new_pass2']; + + $stmt = $pdo->prepare("SELECT `password` FROM `admin` + WHERE `username` = :user"); + $stmt->execute(array(':user' => $username)); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (!verify_ssha256($row['password'], $password_old)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + + if (!empty($password_new2) && !empty($password_new)) { + if ($password_new2 != $password_new) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_mismatch']) + ); + return false; + } + if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['password_complexity']) + ); + return false; + } + $password_hashed = hash_password($password_new); + try { + $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username"); + $stmt->execute(array( + ':password_hashed' => $password_hashed, + ':username' => $username + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars($username)) + ); + } + break; + case 'delete': + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + $usernames = (array)$_data['username']; + foreach ($usernames as $username) { + if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['username_invalid']) + ); + return false; + } + try { + $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); + $stmt->execute(array( + ':username' => $username, + )); + $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username"); + $stmt->execute(array( + ':username' => $username, + )); + } + catch (PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + return false; + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['domain_admin_removed'], htmlspecialchars(implode(', ', $usernames))) + ); + break; + case 'get': + $domainadmins = array(); + if ($_SESSION['mailcow_cc_role'] != "admin") { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + try { + $stmt = $pdo->query("SELECT DISTINCT + `username` + FROM `domain_admins` + WHERE `username` IN ( + SELECT `username` FROM `admin` + WHERE `superadmin`!='1' + )"); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + while ($row = array_shift($rows)) { + $domainadmins[] = $row['username']; + } + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + } + return $domainadmins; + break; + case 'details': + $domainadmindata = array(); + + if ($_SESSION['mailcow_cc_role'] == "domainadmin" && $_data != $_SESSION['mailcow_cc_username']) { + return false; + } + elseif ($_SESSION['mailcow_cc_role'] != "admin" || !isset($_data)) { + return false; + } + + if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $_data))) { + return false; + } + try { + $stmt = $pdo->prepare("SELECT + `tfa`.`active` AS `tfa_active_int`, + CASE `tfa`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `tfa_active`, + `domain_admins`.`username`, + `domain_admins`.`created`, + `domain_admins`.`active` AS `active_int`, + CASE `domain_admins`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active` + FROM `domain_admins` + LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`domain_admins`.`username` + WHERE `domain_admins`.`username`= :domain_admin"); + $stmt->execute(array( + ':domain_admin' => $_data + )); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if (empty($row)) { + return false; + } + $domainadmindata['username'] = $row['username']; + $domainadmindata['tfa_active'] = $row['tfa_active']; + $domainadmindata['active'] = $row['active']; + $domainadmindata['tfa_active_int'] = $row['tfa_active_int']; + $domainadmindata['active_int'] = $row['active_int']; + $domainadmindata['modified'] = $row['created']; + // GET SELECTED + $stmt = $pdo->prepare("SELECT `domain` FROM `domain` + WHERE `domain` IN ( + SELECT `domain` FROM `domain_admins` + WHERE `username`= :domain_admin)"); + $stmt->execute(array(':domain_admin' => $_data)); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + while($row = array_shift($rows)) { + $domainadmindata['selected_domains'][] = $row['domain']; + } + // GET UNSELECTED + $stmt = $pdo->prepare("SELECT `domain` FROM `domain` + WHERE `domain` NOT IN ( + SELECT `domain` FROM `domain_admins` + WHERE `username`= :domain_admin)"); + $stmt->execute(array(':domain_admin' => $_data)); + $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); + while($row = array_shift($rows)) { + $domainadmindata['unselected_domains'][] = $row['domain']; + } + if (!isset($domainadmindata['unselected_domains'])) { + $domainadmindata['unselected_domains'] = ""; + } + } + catch(PDOException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'MySQL: '.$e + ); + } + return $domainadmindata; + break; + } +} \ No newline at end of file diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index b3420530..66dad50f 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -73,7 +73,6 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) { unset($lines[0]); return base64_decode(implode('', $lines)); } - if (empty($starttls)) { $context = stream_context_create(array("ssl" => array("capture_peer_cert" => true, 'verify_peer' => false, 'allow_self_signed' => true))); $stream = stream_socket_client('tls://' . $hostname . ':' . $port, $error_nr, $error_msg, 5, STREAM_CLIENT_CONNECT, $context); @@ -113,7 +112,6 @@ function generate_tlsa_digest($hostname, $port, $starttls = null) { stream_socket_enable_crypto($stream, true, STREAM_CRYPTO_METHOD_ANY_CLIENT); stream_set_blocking($stream, false); } - $params = stream_context_get_params($stream); if (!empty($params['options']['ssl']['peer_certificate'])) { $key_resource = openssl_pkey_get_public($params['options']['ssl']['peer_certificate']); @@ -142,30 +140,6 @@ function verify_ssha256($hash, $password) { return false; } } -function doveadm_authenticate($hash, $algorithm, $password) { - $descr = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')); - $pipes = array(); - $process = proc_open("/usr/bin/doveadm pw -s ".$algorithm." -t '".$hash."'", $descr, $pipes); - if (is_resource($process)) { - fputs($pipes[0], $password); - fclose($pipes[0]); - while ($f = fgets($pipes[1])) { - if (preg_match('/(verified)/', $f)) { - proc_close($process); - return true; - } - return false; - } - fclose($pipes[1]); - while ($f = fgets($pipes[2])) { - proc_close($process); - return false; - } - fclose($pipes[2]); - proc_close($process); - } - return false; -} function check_login($user, $pass) { global $pdo; global $redis; @@ -272,7 +246,6 @@ function edit_admin_account($postarray) { ); return false; } - if (!empty($password) && !empty($password2)) { if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { $_SESSION['return'] = array( @@ -348,28 +321,20 @@ function edit_admin_account($postarray) { function edit_user_account($postarray) { global $lang; global $pdo; - if (isset($postarray['username']) && filter_var($postarray['username'], FILTER_VALIDATE_EMAIL)) { - if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $postarray['username'])) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - else { - $username = $postarray['username']; - } + $username = $_SESSION['mailcow_cc_username']; + $role = $_SESSION['mailcow_cc_role']; + $password_old = $postarray['user_old_pass']; + if (filter_var($username, FILTER_VALIDATE_EMAIL === false) || $role != 'user') { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; } - else { - $username = $_SESSION['mailcow_cc_username']; - } - $password_old = $postarray['user_old_pass']; - if (isset($postarray['user_new_pass']) && isset($postarray['user_new_pass2'])) { $password_new = $postarray['user_new_pass']; $password_new2 = $postarray['user_new_pass2']; } - $stmt = $pdo->prepare("SELECT `password` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `username` = :user"); @@ -382,7 +347,6 @@ function edit_user_account($postarray) { ); return false; } - if (isset($password_new) && isset($password_new2)) { if (!empty($password_new2) && !empty($password_new)) { if ($password_new2 != $password_new) { @@ -486,293 +450,12 @@ function is_valid_domain_name($domain_name) { && preg_match("/^.{1,253}$/", $domain_name) && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name)); } -function add_domain_admin($postarray) { - global $lang; - global $pdo; - $username = strtolower(trim($postarray['username'])); - $password = $postarray['password']; - $password2 = $postarray['password2']; - $domains = (array)$postarray['domains']; - $active = intval($postarray['active']); - - if ($_SESSION['mailcow_cc_role'] != "admin") { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - if (empty($domains)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) - ); - return false; - } - if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username)) || empty ($username)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) - ); - return false; - } - try { - $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` - WHERE `username` = :username"); - $stmt->execute(array(':username' => $username)); - $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); - - $stmt = $pdo->prepare("SELECT `username` FROM `admin` - WHERE `username` = :username"); - $stmt->execute(array(':username' => $username)); - $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); - - $stmt = $pdo->prepare("SELECT `username` FROM `domain_admins` - WHERE `username` = :username"); - $stmt->execute(array(':username' => $username)); - $num_results[] = count($stmt->fetchAll(PDO::FETCH_ASSOC)); - } - catch(PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - foreach ($num_results as $num_results_each) { - if ($num_results_each != 0) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username)) - ); - return false; - } - } - if (!empty($password) && !empty($password2)) { - if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) - ); - return false; - } - if ($password != $password2) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) - ); - return false; - } - $password_hashed = hash_password($password); - foreach ($domains as $domain) { - if (!is_valid_domain_name($domain)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) - ); - return false; - } - try { - $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) - VALUES (:username, :domain, :created, :active)"); - $stmt->execute(array( - ':username' => $username, - ':domain' => $domain, - ':created' => date('Y-m-d H:i:s'), - ':active' => $active - )); - } - catch (PDOException $e) { - delete_domain_admin(array('username' => $username)); - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - try { - $stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`) - VALUES (:username, :password_hashed, '0', :active)"); - $stmt->execute(array( - ':username' => $username, - ':password_hashed' => $password_hashed, - ':active' => $active - )); - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - else { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_empty']) - ); - return false; - } - $_SESSION['return'] = array( - 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_added'], htmlspecialchars($username)) - ); -} -function delete_domain_admin($postarray) { - global $pdo; - global $lang; - if ($_SESSION['mailcow_cc_role'] != "admin") { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - $usernames = (array)$postarray['username']; - foreach ($usernames as $username) { - if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) - ); - return false; - } - try { - $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); - $stmt->execute(array( - ':username' => $username, - )); - $stmt = $pdo->prepare("DELETE FROM `admin` WHERE `username` = :username"); - $stmt->execute(array( - ':username' => $username, - )); - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - $_SESSION['return'] = array( - 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_removed'], htmlspecialchars(implode(', ', $usernames))) - ); -} -function get_domain_admins() { - global $pdo; - global $lang; - $domainadmins = array(); - if ($_SESSION['mailcow_cc_role'] != "admin") { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - try { - $stmt = $pdo->query("SELECT DISTINCT - `username` - FROM `domain_admins` - WHERE `username` IN ( - SELECT `username` FROM `admin` - WHERE `superadmin`!='1' - )"); - $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); - while ($row = array_shift($rows)) { - $domainadmins[] = $row['username']; - } - } - catch(PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - } - return $domainadmins; -} -function get_domain_admin_details($domain_admin) { - global $pdo; - - global $lang; - $domainadmindata = array(); - if (isset($domain_admin) && $_SESSION['mailcow_cc_role'] != "admin") { - return false; - } - if (!isset($domain_admin) && $_SESSION['mailcow_cc_role'] != "domainadmin") { - return false; - } - (!isset($domain_admin)) ? $domain_admin = $_SESSION['mailcow_cc_username'] : null; - - if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $domain_admin))) { - return false; - } - try { - $stmt = $pdo->prepare("SELECT - `tfa`.`active` AS `tfa_active_int`, - CASE `tfa`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `tfa_active`, - `domain_admins`.`username`, - `domain_admins`.`created`, - `domain_admins`.`active` AS `active_int`, - CASE `domain_admins`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active` - FROM `domain_admins` - LEFT OUTER JOIN `tfa` ON `tfa`.`username`=`domain_admins`.`username` - WHERE `domain_admins`.`username`= :domain_admin"); - $stmt->execute(array( - ':domain_admin' => $domain_admin - )); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - return false; - } - $domainadmindata['username'] = $row['username']; - $domainadmindata['tfa_active'] = $row['tfa_active']; - $domainadmindata['active'] = $row['active']; - $domainadmindata['tfa_active_int'] = $row['tfa_active_int']; - $domainadmindata['active_int'] = $row['active_int']; - $domainadmindata['modified'] = $row['created']; - // GET SELECTED - $stmt = $pdo->prepare("SELECT `domain` FROM `domain` - WHERE `domain` IN ( - SELECT `domain` FROM `domain_admins` - WHERE `username`= :domain_admin)"); - $stmt->execute(array(':domain_admin' => $domain_admin)); - $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); - while($row = array_shift($rows)) { - $domainadmindata['selected_domains'][] = $row['domain']; - } - // GET UNSELECTED - $stmt = $pdo->prepare("SELECT `domain` FROM `domain` - WHERE `domain` NOT IN ( - SELECT `domain` FROM `domain_admins` - WHERE `username`= :domain_admin)"); - $stmt->execute(array(':domain_admin' => $domain_admin)); - $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); - while($row = array_shift($rows)) { - $domainadmindata['unselected_domains'][] = $row['domain']; - } - if (!isset($domainadmindata['unselected_domains'])) { - $domainadmindata['unselected_domains'] = ""; - } - } - catch(PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - } - return $domainadmindata; -} function set_tfa($postarray) { global $lang; global $pdo; global $yubi; global $u2f; global $tfa; - if ($_SESSION['mailcow_cc_role'] != "domainadmin" && $_SESSION['mailcow_cc_role'] != "admin") { $_SESSION['return'] = array( @@ -847,7 +530,6 @@ function set_tfa($postarray) { 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars($username)) ); break; - case "u2f": $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"]; try { @@ -871,7 +553,6 @@ function set_tfa($postarray) { return false; } break; - case "totp": $key_id = (!isset($postarray["key_id"])) ? 'unidentified' : $postarray["key_id"]; if ($tfa->verifyCode($_POST['totp_secret'], $_POST['totp_confirm_token']) === true) { @@ -900,7 +581,6 @@ function set_tfa($postarray) { ); } break; - case "none": try { $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username"); @@ -977,7 +657,6 @@ function get_tfa($username = null) { elseif (empty($username)) { return false; } - $stmt = $pdo->prepare("SELECT * FROM `tfa` WHERE `username` = :username AND `active` = '1'"); $stmt->execute(array(':username' => $username)); @@ -1041,7 +720,6 @@ function verify_tfa_login($username, $token) { global $yubi; global $u2f; global $tfa; - $stmt = $pdo->prepare("SELECT `authmech` FROM `tfa` WHERE `username` = :username AND `active` = '1'"); $stmt->execute(array(':username' => $username)); @@ -1126,237 +804,6 @@ function verify_tfa_login($username, $token) { } return false; } -function edit_domain_admin($postarray) { - global $lang; - global $pdo; - - if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - // Administrator - if ($_SESSION['mailcow_cc_role'] == "admin") { - if (!is_array($postarray['username'])) { - $usernames = array(); - $usernames[] = $postarray['username']; - } - else { - $usernames = $postarray['username']; - } - foreach ($usernames as $username) { - $is_now = get_domain_admin_details($username); - $domains = (isset($postarray['domains'])) ? (array)$postarray['domains'] : null; - if (!empty($is_now)) { - $active = (isset($postarray['active'])) ? $postarray['active'] : $is_now['active_int']; - $domains = (!empty($domains)) ? $domains : $is_now['selected_domains']; - $username_new = (!empty($postarray['username_new'])) ? $postarray['username_new'] : $is_now['username']; - } - else { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - $password = $postarray['password']; - $password2 = $postarray['password2']; - - if (!empty($domains)) { - foreach ($domains as $domain) { - if (!is_valid_domain_name($domain)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['domain_invalid']) - ); - return false; - } - } - } - if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username_new))) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) - ); - return false; - } - if ($username_new != $username) { - if (!empty(get_domain_admin_details($username_new)['username'])) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['username_invalid']) - ); - return false; - } - } - try { - $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username"); - $stmt->execute(array( - ':username' => $username, - )); - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - - if (!empty($domains)) { - foreach ($domains as $domain) { - try { - $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`) - VALUES (:username_new, :domain, :created, :active)"); - $stmt->execute(array( - ':username_new' => $username_new, - ':domain' => $domain, - ':created' => date('Y-m-d H:i:s'), - ':active' => $active - )); - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - } - - if (!empty($password) && !empty($password2)) { - if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) - ); - return false; - } - if ($password != $password2) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) - ); - return false; - } - $password_hashed = hash_password($password); - try { - $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active, `password` = :password_hashed WHERE `username` = :username"); - $stmt->execute(array( - ':password_hashed' => $password_hashed, - ':username_new' => $username_new, - ':username' => $username, - ':active' => $active - )); - if (isset($postarray['disable_tfa'])) { - $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); - $stmt->execute(array(':username' => $username)); - } - else { - $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); - $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); - } - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - else { - try { - $stmt = $pdo->prepare("UPDATE `admin` SET `username` = :username_new, `active` = :active WHERE `username` = :username"); - $stmt->execute(array( - ':username_new' => $username_new, - ':username' => $username, - ':active' => $active - )); - if (isset($postarray['disable_tfa'])) { - $stmt = $pdo->prepare("UPDATE `tfa` SET `active` = '0' WHERE `username` = :username"); - $stmt->execute(array(':username' => $username)); - } - else { - $stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username"); - $stmt->execute(array(':username_new' => $username_new, ':username' => $username)); - } - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - } - $_SESSION['return'] = array( - 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars(implode(', ', $usernames))) - ); - } - // Domain administrator - // Can only edit itself - elseif ($_SESSION['mailcow_cc_role'] == "domainadmin") { - $username = $_SESSION['mailcow_cc_username']; - $password_old = $postarray['user_old_pass']; - $password_new = $postarray['user_new_pass']; - $password_new2 = $postarray['user_new_pass2']; - - $stmt = $pdo->prepare("SELECT `password` FROM `admin` - WHERE `username` = :user"); - $stmt->execute(array(':user' => $username)); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - if (!verify_ssha256($row['password'], $password_old)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['access_denied']) - ); - return false; - } - - if (!empty($password_new2) && !empty($password_new)) { - if ($password_new2 != $password_new) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_mismatch']) - ); - return false; - } - if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password_new)) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['password_complexity']) - ); - return false; - } - $password_hashed = hash_password($password_new); - try { - $stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username"); - $stmt->execute(array( - ':password_hashed' => $password_hashed, - ':username' => $username - )); - } - catch (PDOException $e) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => 'MySQL: '.$e - ); - return false; - } - } - - $_SESSION['return'] = array( - 'type' => 'success', - 'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars($username)) - ); - } -} function get_admin_details() { // No parameter to be given, only one admin should exist global $pdo; @@ -1438,4 +885,4 @@ function get_logs($container, $lines = 100) { } return false; } -?> +?> \ No newline at end of file diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 597d9d87..de8bf0ac 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -879,7 +879,7 @@ function mailbox($_action, $_type, $_data = null) { $alias_domain = idn_to_ascii(strtolower(trim($alias_domain))); $is_now = mailbox('get', 'alias_domain_details', $alias_domain); if (!empty($is_now)) { - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; $target_domain = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain']))) : $is_now['target_domain']; } else { @@ -903,7 +903,7 @@ function mailbox($_action, $_type, $_data = null) { ); return false; } - if (empty(mailbox('get', 'domain_details', $target_domain))) { + if (empty(mailbox('get', 'domain_details', $target_domain)) || !empty(mailbox('get', 'alias_domain_details', $target_domain))) { $_SESSION['return'] = array( 'type' => 'danger', 'msg' => sprintf($lang['danger']['target_domain_invalid']) @@ -950,12 +950,10 @@ function mailbox($_action, $_type, $_data = null) { ); return false; } - $tls_enforce_out = intval($_data['tls_enforce_out']); - $tls_enforce_in = intval($_data['tls_enforce_in']); $is_now = mailbox('get', 'tls_policy', $username); if (!empty($is_now)) { - $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? $_data['tls_enforce_in'] : $is_now['tls_enforce_in']; - $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? $_data['tls_enforce_out'] : $is_now['tls_enforce_out']; + $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in']; + $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? intval($_data['tls_enforce_out']) : $is_now['tls_enforce_out']; } else { $_SESSION['return'] = array( @@ -1136,6 +1134,63 @@ function mailbox($_action, $_type, $_data = null) { 'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames)) ); break; + case 'domain_ratelimit': + $rl_value = intval($_data['rl_value']); + $rl_frame = $_data['rl_frame']; + if (!in_array($rl_frame, array('s', 'm', 'h'))) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Ratelimit time frame is incorrect' + ); + return false; + } + if (!is_array($_data['domain'])) { + $domains = array(); + $domains[] = $_data['domain']; + } + else { + $domains = $_data['domain']; + } + foreach ($domains as $domain) { + if (!is_valid_domain_name($domain) || !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => sprintf($lang['danger']['access_denied']) + ); + return false; + } + if (empty($rl_value)) { + try { + $redis->hDel('RL_OBJECT', $domain); + $redis->hDel('RL_VALUE', $domain); + } + catch (RedisException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Redis: '.$e + ); + return false; + } + } + else { + try { + $redis->hSet('RL_OBJECT', $domain, '1'); + $redis->hSet('RL_VALUE', $domain, $rl_value . ' / 1' . $rl_frame); + } + catch (RedisException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Redis: '.$e + ); + return false; + } + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['domain_modified'], implode(', ', $domains)) + ); + break; case 'syncjob': if (!is_array($_data['id'])) { $ids = array(); @@ -1149,9 +1204,9 @@ function mailbox($_action, $_type, $_data = null) { if (!empty($is_now)) { $username = $is_now['user2']; $user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1']; - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; - $delete2duplicates = (isset($_data['delete2duplicates'])) ? $_data['delete2duplicates'] : $is_now['delete2duplicates']; - $delete1 = (isset($_data['delete1'])) ? $_data['delete1'] : $is_now['delete1']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + $delete2duplicates = (isset($_data['delete2duplicates'])) ? intval($_data['delete2duplicates']) : $is_now['delete2duplicates']; + $delete1 = (isset($_data['delete1'])) ? intval($_data['delete1']) : $is_now['delete1']; $port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1']; $password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1']; $host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1']; @@ -1253,7 +1308,7 @@ function mailbox($_action, $_type, $_data = null) { foreach ($addresses as $address) { $is_now = mailbox('get', 'alias_details', $address); if (!empty($is_now)) { - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; $goto = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto']; } else { @@ -1383,9 +1438,9 @@ function mailbox($_action, $_type, $_data = null) { elseif ($_SESSION['mailcow_cc_role'] == "admin") { $is_now = mailbox('get', 'domain_details', $domain); if (!empty($is_now)) { - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; - $backupmx = (isset($_data['backupmx'])) ? $_data['backupmx'] : $is_now['backupmx_int']; - $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? $_data['relay_all_recipients'] : $is_now['relay_all_recipients_int']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + $backupmx = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : $is_now['backupmx_int']; + $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : $is_now['relay_all_recipients_int']; $aliases = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain']; $mailboxes = (!empty($_data['mailboxes'])) ? $_data['mailboxes'] : $is_now['max_num_mboxes_for_domain']; $maxquota = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_quota_for_mbox'] / 1048576); @@ -1524,7 +1579,7 @@ function mailbox($_action, $_type, $_data = null) { } $is_now = mailbox('get', 'mailbox_details', $username); if (!empty($is_now)) { - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; $name = (!empty($_data['name'])) ? $_data['name'] : $is_now['name']; $domain = $is_now['domain']; $quota_m = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['quota'] / 1048576); @@ -1588,19 +1643,15 @@ function mailbox($_action, $_type, $_data = null) { mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro'] ); // Get sender_acl items from POST array - $sender_acl_domain_admin = ($_data['sender_acl'] == "0") ? array() : $_data['sender_acl']; + $sender_acl_domain_admin = ($_data['sender_acl'] == "0") ? array() : (array)$_data['sender_acl']; if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) { - // Check items in POST array - foreach ($sender_acl_domain_admin as $sender_acl) { - if (!filter_var($sender_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($sender_acl, '@'))) { - $_SESSION['return'] = array( - 'type' => 'danger', - 'msg' => sprintf($lang['danger']['sender_acl_invalid']) - ); - return false; + // Check items in POST array and skip invalid + foreach ($sender_acl_domain_admin as $key => $val) { + if (!filter_var($val, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($val, '@'))) { + unset($sender_acl_domain_admin[$key]); } - if (is_valid_domain_name(ltrim($sender_acl, '@'))) { - if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], ltrim($sender_acl, '@'))) { + if (is_valid_domain_name(ltrim($val, '@'))) { + if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], ltrim($val, '@'))) { $_SESSION['return'] = array( 'type' => 'danger', 'msg' => sprintf($lang['danger']['sender_acl_invalid']) @@ -1608,8 +1659,8 @@ function mailbox($_action, $_type, $_data = null) { return false; } } - if (filter_var($sender_acl, FILTER_VALIDATE_EMAIL)) { - if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $sender_acl)) { + if (filter_var($val, FILTER_VALIDATE_EMAIL)) { + if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $val)) { $_SESSION['return'] = array( 'type' => 'danger', 'msg' => sprintf($lang['danger']['sender_acl_invalid']) @@ -1761,8 +1812,8 @@ function mailbox($_action, $_type, $_data = null) { foreach ($names as $name) { $is_now = mailbox('get', 'resource_details', $name); if (!empty($is_now)) { - $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int']; - $multiple_bookings = (isset($_data['multiple_bookings'])) ? $_data['multiple_bookings'] : $is_now['multiple_bookings_int']; + $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int']; + $multiple_bookings = (isset($_data['multiple_bookings'])) ? intval($_data['multiple_bookings']) : $is_now['multiple_bookings_int']; $description = (!empty($_data['description'])) ? $_data['description'] : $is_now['description']; $kind = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind']; } @@ -2267,6 +2318,31 @@ function mailbox($_action, $_type, $_data = null) { } return $aliases; break; + case 'domain_ratelimit': + $aliases = array(); + if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) { + return false; + } + try { + if (($rl_value = $redis->hGet('RL_VALUE', $_data)) && $redis->hGet('RL_OBJECT', $_data)) { + $rl = explode(' / 1', $rl_value); + $data['value'] = $rl[0]; + $data['frame'] = $rl[1]; + return $data; + } + else { + return false; + } + } + catch (RedisException $e) { + $_SESSION['return'] = array( + 'type' => 'danger', + 'msg' => 'Redis: '.$e + ); + return false; + } + return false; + break; case 'alias_details': $aliasdata = array(); try { diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index e00fd31a..ebc453f8 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -61,6 +61,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.php'; include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php'; +require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php'; require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php'; diff --git a/data/web/inc/sessions.inc.php b/data/web/inc/sessions.inc.php index e2919f7a..d23d2cba 100644 --- a/data/web/inc/sessions.inc.php +++ b/data/web/inc/sessions.inc.php @@ -1,6 +1,8 @@ diff --git a/data/web/js/api.js b/data/web/js/api.js index ec26709a..1fd962fb 100644 --- a/data/web/js/api.js +++ b/data/web/js/api.js @@ -64,8 +64,23 @@ $(document).ready(function() { // If clicked element #edit_selected is in a form with the same data-id as the button, // we merge all input fields by {"name":"value"} into api-attr if ($(this).closest("form").data('id') == id) { - var attr_to_merge = $(this).closest("form").serializeObject(); - var api_attr = $.extend(api_attr, attr_to_merge) + var req_empty = false; + $(this).closest("form").find('select, textarea, input').each(function() { + if ($(this).prop('required')) { + if (!$(this).val()) { + req_empty = true; + $(this).addClass('inputMissingAttr'); + } else { + $(this).removeClass('inputMissingAttr'); + } + } + }); + if (!req_empty) { + var attr_to_merge = $(this).closest("form").serializeObject(); + var api_attr = $.extend(api_attr, attr_to_merge) + } else { + return false; + } } // If clicked element #edit_selected has data-item attribute, it is added to "items" if (typeof $(this).data('item') !== 'undefined') { @@ -77,6 +92,7 @@ $(document).ready(function() { } if (typeof multi_data[id] == "undefined") return; api_items = multi_data[id]; + // alert(JSON.stringify(api_attr)); if (Object.keys(api_items).length !== 0) { $.ajax({ type: "POST", diff --git a/data/web/json_api.php b/data/web/json_api.php index e4086520..56d4e741 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -426,7 +426,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u case "domain-admin": if (isset($_POST['attr'])) { $attr = (array)json_decode($_POST['attr'], true); - if (add_domain_admin($attr) === false) { + if (domain_admin('add', $attr) === false) { if (isset($_SESSION['return'])) { echo json_encode($_SESSION['return']); } @@ -826,10 +826,10 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u case "domain-admin": switch ($object) { case "all": - $domain_admins = get_domain_admins(); + $domain_admins = domain_admin('get'); if (!empty($domain_admins)) { foreach ($domain_admins as $domain_admin) { - if ($details = get_domain_admin_details($domain_admin)) { + if ($details = domain_admin('details', $domain_admin)) { $data[] = $details; } else { @@ -849,7 +849,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u break; default: - $data = get_domain_admin_details($object); + $data = domain_admin('details', $object); if (!isset($data) || empty($data)) { echo '{}'; } @@ -1385,7 +1385,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u if (isset($_POST['items'])) { $items = (array)json_decode($_POST['items'], true); if (is_array($items)) { - if (delete_domain_admin(array('username' => $items)) === false) { + if (domain_admin('delete', array('username' => $items)) === false) { if (isset($_SESSION['return'])) { echo json_encode($_SESSION['return']); } @@ -1603,6 +1603,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u } break; case "mailbox": + // sender_acl:0 removes all entries if (isset($_POST['items']) && isset($_POST['attr'])) { $items = (array)json_decode($_POST['items'], true); $attr = (array)json_decode($_POST['attr'], true); @@ -1778,6 +1779,50 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u )); } break; + case "domain-ratelimit": + if (isset($_POST['items']) && isset($_POST['attr'])) { + $items = (array)json_decode($_POST['items'], true); + $attr = (array)json_decode($_POST['attr'], true); + $postarray = array_merge(array('domain' => $items), $attr); + if (is_array($postarray['domain'])) { + if (mailbox('edit', 'domain_ratelimit', $postarray) === false) { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Edit failed' + )); + } + exit(); + } + else { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'success', + 'msg' => 'Task completed' + )); + } + } + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Incomplete post data' + )); + } + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Incomplete post data' + )); + } + break; case "alias-domain": if (isset($_POST['items']) && isset($_POST['attr'])) { $items = (array)json_decode($_POST['items'], true); @@ -1822,7 +1867,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u )); } break; - case "spam_score": + case "spam-score": if (isset($_POST['items']) && isset($_POST['attr'])) { $items = (array)json_decode($_POST['items'], true); $attr = (array)json_decode($_POST['attr'], true); @@ -1872,7 +1917,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u $attr = (array)json_decode($_POST['attr'], true); $postarray = array_merge(array('username' => $items), $attr); if (is_array($postarray['username'])) { - if (edit_domain_admin($postarray) === false) { + if (domain_admin('edit', $postarray) === false) { if (isset($_SESSION['return'])) { echo json_encode($_SESSION['return']); } @@ -1989,39 +2034,109 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u )); } break; - case "admin": - // No items as there is only one admin - if (isset($_POST['attr'])) { - $attr = (array)json_decode($_POST['attr'], true); - if (edit_admin_account($attr) === false) { - if (isset($_SESSION['return'])) { - echo json_encode($_SESSION['return']); + case "self": + // No items, logged-in user, users and domain admins + if ($_SESSION['mailcow_cc_role'] == "domainadmin") { + if (isset($_POST['attr'])) { + $attr = (array)json_decode($_POST['attr'], true); + if (domain_admin('edit', $attr) === false) { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Edit failed' + )); + } + exit(); } else { - echo json_encode(array( - 'type' => 'error', - 'msg' => 'Edit failed' - )); + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'success', + 'msg' => 'Task completed' + )); + } } - exit(); } else { - if (isset($_SESSION['return'])) { - echo json_encode($_SESSION['return']); - } - else { - echo json_encode(array( - 'type' => 'success', - 'msg' => 'Task completed' - )); - } + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Incomplete post data' + )); } } - else { - echo json_encode(array( - 'type' => 'error', - 'msg' => 'Incomplete post data' - )); + elseif ($_SESSION['mailcow_cc_role'] == "user") { + if (isset($_POST['attr'])) { + $attr = (array)json_decode($_POST['attr'], true); + if (edit_user_account($attr) === false) { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Edit failed' + )); + } + exit(); + } + else { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'success', + 'msg' => 'Task completed' + )); + } + } + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Incomplete post data' + )); + } + } + elseif ($_SESSION['mailcow_cc_role'] == "admin") { + if (isset($_POST['attr'])) { + $attr = (array)json_decode($_POST['attr'], true); + if (edit_admin_account($attr) === false) { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Edit failed' + )); + } + exit(); + } + else { + if (isset($_SESSION['return'])) { + echo json_encode($_SESSION['return']); + } + else { + echo json_encode(array( + 'type' => 'success', + 'msg' => 'Task completed' + )); + } + } + } + else { + echo json_encode(array( + 'type' => 'error', + 'msg' => 'Incomplete post data' + )); + } } break; } diff --git a/data/web/user.php b/data/web/user.php index 77ccc62d..b283894c 100644 --- a/data/web/user.php +++ b/data/web/user.php @@ -357,7 +357,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "use