[Compose] Update watchdog image
[Watchdog] Fix IP detection with multiple networks [Web] Show API field (no docs, no support, wip) [Web] haveibeenpwned.com implementation [Web] User and domain admin ACL (no docs, no support, wip) [Web] Some minor fixes
This commit is contained in:
@@ -12,10 +12,20 @@ logger();
|
||||
<script src="/js/formcache.min.js"></script>
|
||||
<script src="/js/google.charts.loader.js"></script>
|
||||
<script src="/js/numberedtextarea.min.js"></script>
|
||||
<script src="/js/sha1.min.js"></script>
|
||||
<script src="/js/u2f-api.js"></script>
|
||||
<script src="/js/api.js"></script>
|
||||
<script src="/js/mailcow.js"></script>
|
||||
<script>
|
||||
var loading_text = '<?= $lang['footer']['loading']; ?>'
|
||||
<?php
|
||||
$lang_footer = json_encode($lang['footer']);
|
||||
$lang_acl = json_encode($lang['acl']);
|
||||
$lang_tfa = json_encode($lang['tfa']);
|
||||
echo "var lang_footer = ". $lang_footer . ";\n";
|
||||
echo "var lang_acl = ". $lang_acl . ";\n";
|
||||
echo "var lang_tfa = ". $lang_tfa . ";\n";
|
||||
echo "var docker_timeout = ". $DOCKER_TIMEOUT * 1000 . ";\n";
|
||||
?>
|
||||
$(window).scroll(function() {
|
||||
sessionStorage.scrollTop = $(this).scrollTop();
|
||||
});
|
||||
@@ -28,17 +38,8 @@ $(window).load(function() {
|
||||
$(".overlay").hide();
|
||||
});
|
||||
$(document).ready(function() {
|
||||
window.mailcow_alert_box = function(message, type) {
|
||||
msg = $('<span/>').text(message).text();
|
||||
if (type == 'danger') {
|
||||
auto_hide = 0;
|
||||
$('#' + localStorage.getItem("add_modal")).modal('show');
|
||||
localStorage.removeItem("add_modal");
|
||||
} else {
|
||||
auto_hide = 5000;
|
||||
}
|
||||
$.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}});
|
||||
}
|
||||
// TFA, CSRF, Alerts in footer.inc.php
|
||||
// Other general functions in mailcow.js
|
||||
<?php
|
||||
$alertbox_log_parser = alertbox_log_parser($_SESSION);
|
||||
if (is_array($alertbox_log_parser)) {
|
||||
@@ -50,7 +51,6 @@ $(document).ready(function() {
|
||||
unset($_SESSION['return']);
|
||||
}
|
||||
?>
|
||||
$('[data-cached-form="true"]').formcache({key: $(this).data('id')});
|
||||
// Confirm TFA modal
|
||||
<?php if (isset($_SESSION['pending_tfa_method'])):?>
|
||||
$('#ConfirmTFAModal').modal({
|
||||
@@ -68,7 +68,7 @@ $(document).ready(function() {
|
||||
dataType: 'script',
|
||||
url: "/api/v1/get/u2f-authentication/<?= (isset($_SESSION['pending_mailcow_cc_username'])) ? rawurlencode($_SESSION['pending_mailcow_cc_username']) : null; ?>",
|
||||
complete: function(data){
|
||||
$('#u2f_status_auth').html('<?=$lang['tfa']['waiting_usb_auth'];?>');
|
||||
$('#u2f_status_auth').html(lang_tfa.waiting_usb_auth);
|
||||
data;
|
||||
setTimeout(function() {
|
||||
console.log("Ready to authenticate");
|
||||
@@ -98,7 +98,6 @@ $(document).ready(function() {
|
||||
<?php endif; ?>
|
||||
|
||||
// Set TFA modals
|
||||
|
||||
$('#selectTFA').change(function () {
|
||||
if ($(this).val() == "yubi_otp") {
|
||||
$('#YubiOTPModal').modal('show');
|
||||
@@ -121,7 +120,7 @@ $(document).ready(function() {
|
||||
data;
|
||||
setTimeout(function() {
|
||||
console.log("Ready to register");
|
||||
$('#u2f_status_reg').html('<?=$lang['tfa']['waiting_usb_register'];?>');
|
||||
$('#u2f_status_reg').html(lang_tfa.waiting_usb_register);
|
||||
u2f.register(appId, registerRequests, registeredKeys, function(deviceResponse) {
|
||||
var form = document.getElementById('u2f_reg_form');
|
||||
var reg = document.getElementById('u2f_register_data');
|
||||
@@ -146,92 +145,6 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
});
|
||||
|
||||
// Remember last navigation pill
|
||||
(function () {
|
||||
'use strict';
|
||||
if ($('a[data-toggle="tab"]').length) {
|
||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
if ($(this).data('dont-remember') == 1) {
|
||||
return true;
|
||||
}
|
||||
var id = $(this).parents('[role="tablist"]').attr('id');
|
||||
var key = 'lastTag';
|
||||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
localStorage.setItem(key, $(e.target).attr('href'));
|
||||
});
|
||||
$('[role="tablist"]').each(function (idx, elem) {
|
||||
var id = $(elem).attr('id');
|
||||
var key = 'lastTag';
|
||||
if (id) {
|
||||
key += ':' + id;
|
||||
}
|
||||
var lastTab = localStorage.getItem(key);
|
||||
if (lastTab) {
|
||||
$('[href="' + lastTab + '"]').tab('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
// Disable submit after submitting form (not API driven buttons)
|
||||
$('form').submit(function() {
|
||||
if ($('form button[type="submit"]').data('submitted') == '1') {
|
||||
return false;
|
||||
} else {
|
||||
$(this).find('button[type="submit"]').first().text('<?= $lang['footer']['loading']; ?>');
|
||||
$('form button[type="submit"]').attr('data-submitted', '1');
|
||||
function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); };
|
||||
$(document).on("keydown", disableF5);
|
||||
}
|
||||
});
|
||||
|
||||
// IE fix to hide scrollbars when table body is empty
|
||||
$('tbody').filter(function (index) {
|
||||
return $(this).children().length < 1;
|
||||
}).remove();
|
||||
|
||||
// Init Bootstrap Selectpicker
|
||||
$('select').selectpicker();
|
||||
|
||||
// Trigger container restart
|
||||
$('#RestartContainer').on('show.bs.modal', function(e) {
|
||||
var container = $(e.relatedTarget).data('container');
|
||||
$('#containerName').text(container);
|
||||
$('#triggerRestartContainer').click(function(){
|
||||
$(this).prop("disabled",true);
|
||||
$(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
|
||||
$('#statusTriggerRestartContainer').html('<?= $lang['footer']['restarting_container']; ?>');
|
||||
$.ajax({
|
||||
method: 'get',
|
||||
url: '/inc/ajax/container_ctrl.php',
|
||||
timeout: <?= $DOCKER_TIMEOUT * 1000; ?>,
|
||||
data: {
|
||||
'service': container,
|
||||
'action': 'restart'
|
||||
}
|
||||
})
|
||||
.always( function (data, status) {
|
||||
$('#statusTriggerRestartContainer').append(data);
|
||||
var htmlResponse = $.parseHTML(data)
|
||||
if ($(htmlResponse).find('span').hasClass('text-success')) {
|
||||
$('#triggerRestartContainer').html('<span class="glyphicon glyphicon-ok"></span> ');
|
||||
setTimeout(function(){
|
||||
$('#RestartContainer').modal('toggle');
|
||||
window.location = window.location.href.split("#")[0];
|
||||
}, 1200);
|
||||
} else {
|
||||
$('#triggerRestartContainer').html('<span class="glyphicon glyphicon-remove"></span> ');
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
// CSRF
|
||||
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form');
|
||||
if (sessionStorage.scrollTop != "undefined") {
|
||||
|
216
data/web/inc/functions.acl.inc.php
Normal file
216
data/web/inc/functions.acl.inc.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
function acl($_action, $_scope = null, $_data = null) {
|
||||
global $pdo;
|
||||
global $lang;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
case 'edit':
|
||||
switch ($_scope) {
|
||||
case 'user':
|
||||
if (!is_array($_data['username'])) {
|
||||
$usernames = array();
|
||||
$usernames[] = $_data['username'];
|
||||
}
|
||||
else {
|
||||
$usernames = $_data['username'];
|
||||
}
|
||||
foreach ($usernames as $username) {
|
||||
// Cast to array for single selections
|
||||
$acls = (array)$_data['user_acl'];
|
||||
// Create associative array from index array
|
||||
// All set items are given 1 as value
|
||||
foreach ($acls as $acl_key => $acl_val) {
|
||||
$acl_post[$acl_val] = 1;
|
||||
}
|
||||
// Users cannot change their own ACL
|
||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)
|
||||
|| ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin')) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// Read all available acl options by calling acl(get)
|
||||
// Set all available acl options we cannot find in the post data to 0, else 1
|
||||
$is_now = acl('get', 'user', $username);
|
||||
if (!empty($is_now)) {
|
||||
foreach ($is_now as $acl_now_name => $acl_now_val) {
|
||||
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'Cannot determine current ACL'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
foreach ($set_acls as $set_acl_key => $set_acl_val) {
|
||||
$stmt = $pdo->prepare("UPDATE `user_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
|
||||
WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
));
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('acl_saved', $username)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'domainadmin':
|
||||
if ($_SESSION['mailcow_cc_role'] != 'admin') {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!is_array($_data['username'])) {
|
||||
$usernames = array();
|
||||
$usernames[] = $_data['username'];
|
||||
}
|
||||
else {
|
||||
$usernames = $_data['username'];
|
||||
}
|
||||
foreach ($usernames as $username) {
|
||||
// Cast to array for single selections
|
||||
$acls = (array)$_data['da_acl'];
|
||||
// Create associative array from index array
|
||||
// All set items are given 1 as value
|
||||
foreach ($acls as $acl_key => $acl_val) {
|
||||
$acl_post[$acl_val] = 1;
|
||||
}
|
||||
// Users cannot change their own ACL
|
||||
if ($_SESSION['mailcow_cc_role'] != 'admin') {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// Read all available acl options by calling acl(get)
|
||||
// Set all available acl options we cannot find in the post data to 0, else 1
|
||||
$is_now = acl('get', 'domainadmin', $username);
|
||||
if (!empty($is_now)) {
|
||||
foreach ($is_now as $acl_now_name => $acl_now_val) {
|
||||
$set_acls[$acl_now_name] = (isset($acl_post[$acl_now_name])) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'Cannot determine current ACL'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
foreach ($set_acls as $set_acl_key => $set_acl_val) {
|
||||
$stmt = $pdo->prepare("UPDATE `da_acl` SET " . $set_acl_key . " = " . intval($set_acl_val) . "
|
||||
WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
));
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('acl_saved', $username)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'get':
|
||||
switch ($_scope) {
|
||||
case 'user':
|
||||
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $_data));
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($data)) {
|
||||
unset($data['username']);
|
||||
return $data;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'domainadmin':
|
||||
if ($_SESSION['mailcow_cc_role'] != 'admin' && $_SESSION['mailcow_cc_role'] != 'domainadmin') {
|
||||
return false;
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == 'domainadmin' && $_SESSION['mailcow_cc_username'] != $_data) {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $_data));
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($data)) {
|
||||
unset($data['username']);
|
||||
return $data;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'to_session':
|
||||
if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||
return false;
|
||||
}
|
||||
unset($_SESSION['acl']);
|
||||
$username = strtolower(trim($_SESSION['mailcow_cc_username']));
|
||||
// Admins get access to all modules
|
||||
if ($_SESSION['mailcow_cc_role'] == 'admin' ||
|
||||
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'admin')) {
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
|
||||
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($acl_all)) {
|
||||
$acl['acl'][$row['Field']] = 1;
|
||||
}
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM `da_acl` WHERE `Field` != 'username';");
|
||||
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($acl_all)) {
|
||||
$acl['acl'][$row['Field']] = 1;
|
||||
}
|
||||
}
|
||||
elseif ($_SESSION['mailcow_cc_role'] == 'domainadmin' ||
|
||||
(isset($_SESSION["dual-login"]["role"]) && $_SESSION["dual-login"]["role"] == 'domainadmin')) {
|
||||
// Read all exting user_acl modules and set to 1
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
|
||||
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($acl_all)) {
|
||||
$acl['acl'][$row['Field']] = 1;
|
||||
}
|
||||
// Read da_acl rules for current user, OVERWRITE overlapping modules
|
||||
// This prevents access to a users sync jobs, when a domain admins was not given access to sync jobs
|
||||
$stmt = $pdo->prepare("SELECT * FROM `da_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => (isset($_SESSION["dual-login"]["username"])) ? $_SESSION["dual-login"]["username"] : $username));
|
||||
$acl_user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
foreach ($acl_user as $acl_user_key => $acl_user_val) {
|
||||
$acl['acl'][$acl_user_key] = $acl_user_val;
|
||||
}
|
||||
unset($acl['acl']['username']);
|
||||
}
|
||||
elseif ($_SESSION['mailcow_cc_role'] == 'user') {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
unset($acl['acl']['username']);
|
||||
}
|
||||
if (!empty($acl)) {
|
||||
$_SESSION = array_merge($_SESSION, $acl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
@@ -233,6 +233,14 @@ function bcc($_action, $_data = null, $attr = null) {
|
||||
return $bccdata;
|
||||
break;
|
||||
case 'delete':
|
||||
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$ids = (array)$_data['id'];
|
||||
foreach ($ids as $id) {
|
||||
if (!is_numeric($id)) {
|
||||
@@ -279,6 +287,14 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
}
|
||||
switch ($_action) {
|
||||
case 'add':
|
||||
if (!isset($_SESSION['acl']['recipient_maps']) || $_SESSION['acl']['recipient_maps'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$old_dest = strtolower(trim($_data['recipient_map_old']));
|
||||
if (substr($old_dest, 0, 1) == '@') {
|
||||
$old_dest = substr($old_dest, 1);
|
||||
@@ -343,6 +359,14 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
);
|
||||
break;
|
||||
case 'edit':
|
||||
if (!isset($_SESSION['acl']['recipient_maps']) || $_SESSION['acl']['recipient_maps'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$ids = (array)$_data['id'];
|
||||
foreach ($ids as $id) {
|
||||
$is_now = recipient_map('details', $id);
|
||||
@@ -458,6 +482,14 @@ function recipient_map($_action, $_data = null, $attr = null) {
|
||||
return $mapdata;
|
||||
break;
|
||||
case 'delete':
|
||||
if (!isset($_SESSION['acl']['recipient_maps']) || $_SESSION['acl']['recipient_maps'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$ids = (array)$_data['id'];
|
||||
foreach ($ids as $id) {
|
||||
if (!is_numeric($id)) {
|
||||
|
@@ -90,43 +90,22 @@ function domain_admin($_action, $_data = null) {
|
||||
);
|
||||
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',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
$stmt = $pdo->prepare("INSERT INTO `admin` (`username`, `password`, `superadmin`, `active`)
|
||||
VALUES (:username, :password_hashed, '0', :active)");
|
||||
$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
|
||||
VALUES (:username, :domain, :created, :active)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
':password_hashed' => $password_hashed,
|
||||
':domain' => $domain,
|
||||
':created' => date('Y-m-d H:i:s'),
|
||||
':active' => $active
|
||||
));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$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
|
||||
));
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -136,6 +115,10 @@ function domain_admin($_action, $_data = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("INSERT INTO `da_acl` (`username`) VALUES (:username)");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
@@ -209,41 +192,20 @@ function domain_admin($_action, $_data = null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
));
|
||||
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',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$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
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,56 +227,36 @@ function domain_admin($_action, $_data = null) {
|
||||
continue;
|
||||
}
|
||||
$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));
|
||||
}
|
||||
$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));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
continue;
|
||||
else {
|
||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
|
||||
$stmt->execute(array(':username_new' => $username_new, ':username' => $username));
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
$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));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
continue;
|
||||
else {
|
||||
$stmt = $pdo->prepare("UPDATE `tfa` SET `username` = :username_new WHERE `username` = :username");
|
||||
$stmt->execute(array(':username_new' => $username_new, ':username' => $username));
|
||||
}
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -365,21 +307,11 @@ function domain_admin($_action, $_data = null) {
|
||||
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',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("UPDATE `admin` SET `password` = :password_hashed WHERE `username` = :username");
|
||||
$stmt->execute(array(
|
||||
':password_hashed' => $password_hashed,
|
||||
':username' => $username
|
||||
));
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
@@ -407,24 +339,14 @@ function domain_admin($_action, $_data = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
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',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('mysql_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$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,
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
|
@@ -373,54 +373,6 @@ function check_login($user, $pass) {
|
||||
sleep($_SESSION['ldelay']);
|
||||
return false;
|
||||
}
|
||||
function set_acl() {
|
||||
global $pdo;
|
||||
if (!isset($_SESSION['mailcow_cc_username'])) {
|
||||
return false;
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
|
||||
$stmt = $pdo->query("SHOW COLUMNS FROM `user_acl` WHERE `Field` != 'username';");
|
||||
$acl_all = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
while ($row = array_shift($acl_all)) {
|
||||
$acl['acl'][$row['Field']] = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$username = strtolower(trim($_SESSION['mailcow_cc_username']));
|
||||
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$acl['acl'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
unset($acl['acl']['username']);
|
||||
}
|
||||
if (!empty($acl)) {
|
||||
$_SESSION = array_merge($_SESSION, $acl);
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'info',
|
||||
'log' => array(__FUNCTION__),
|
||||
'msg' => 'set_acl_failed'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function get_acl($username) {
|
||||
global $pdo;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
return false;
|
||||
}
|
||||
$username = strtolower(trim($username));
|
||||
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$acl = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
unset($acl['username']);
|
||||
if (!empty($acl)) {
|
||||
return $acl;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function formatBytes($size, $precision = 2) {
|
||||
if(!is_numeric($size)) {
|
||||
return "0";
|
||||
@@ -1266,7 +1218,7 @@ function get_admin_details() {
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->query("SELECT `admin`.`username`, `api`.`active` AS `api_active`, `api`.`api_key`, `api`.`allow_from` FROM `admin`
|
||||
INNER JOIN `api` ON `admin`.`username` = `api`.`username`
|
||||
LEFT OUTER JOIN `api` ON `admin`.`username` = `api`.`username`
|
||||
WHERE `admin`.`superadmin`='1'
|
||||
AND `admin`.`active`='1'");
|
||||
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
@@ -139,7 +139,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$stmt = $pdo->prepare("UPDATE `sieve_filters` SET `script_name` = 'inactive' WHERE `username` = :username AND `filter_type` = :filter_type");
|
||||
$stmt->execute(array(
|
||||
':username' => $username,
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
':filter_type' => $filter_type
|
||||
));
|
||||
}
|
||||
@@ -1453,14 +1452,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
}
|
||||
break;
|
||||
case 'filter':
|
||||
$sieve = new Sieve\SieveParser();
|
||||
if (!is_array($_data['id'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['id'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['id'];
|
||||
}
|
||||
if (!isset($_SESSION['acl']['filters']) || $_SESSION['acl']['filters'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
@@ -1469,6 +1460,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$sieve = new Sieve\SieveParser();
|
||||
if (!is_array($_data['id'])) {
|
||||
$ids = array();
|
||||
$ids[] = $_data['id'];
|
||||
}
|
||||
else {
|
||||
$ids = $_data['id'];
|
||||
}
|
||||
foreach ($ids as $id) {
|
||||
$is_now = mailbox('get', 'filter_details', $id);
|
||||
if (!empty($is_now)) {
|
||||
|
@@ -6,6 +6,14 @@ function policy($_action, $_scope, $_data = null) {
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
case 'add':
|
||||
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
switch ($_scope) {
|
||||
case 'domain':
|
||||
$object = $_data['domain'];
|
||||
@@ -90,14 +98,6 @@ function policy($_action, $_scope, $_data = null) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($_data['object_list'] == "bl") {
|
||||
$object_list = "blacklist_from";
|
||||
}
|
||||
@@ -151,6 +151,14 @@ function policy($_action, $_scope, $_data = null) {
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
switch ($_scope) {
|
||||
case 'domain':
|
||||
(array)$prefids = $_data['prefid'];
|
||||
@@ -215,14 +223,6 @@ function policy($_action, $_scope, $_data = null) {
|
||||
else {
|
||||
$prefids = $_data['prefid'];
|
||||
}
|
||||
if (!isset($_SESSION['acl']['spam_policy']) || $_SESSION['acl']['spam_policy'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
foreach ($prefids as $prefid) {
|
||||
if (!is_numeric($prefid)) {
|
||||
$_SESSION['return'][] = array(
|
||||
|
@@ -5,6 +5,14 @@ function ratelimit($_action, $_scope, $_data = null) {
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
case 'edit':
|
||||
if (!isset($_SESSION['acl']['ratelimit']) || $_SESSION['acl']['ratelimit'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
switch ($_scope) {
|
||||
case 'domain':
|
||||
if (!is_array($_data['object'])) {
|
||||
|
@@ -3,7 +3,7 @@ function init_db_schema() {
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "19082018_1004";
|
||||
$db_version = "01092018_1902";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@@ -280,10 +280,7 @@ function init_db_schema() {
|
||||
"delimiter_action" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"recipient_maps" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
@@ -300,6 +297,32 @@ function init_db_schema() {
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"da_acl" => array(
|
||||
"cols" => array(
|
||||
"username" => "VARCHAR(255) NOT NULL",
|
||||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"login_as" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"ratelimit" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"spam_policy" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
"" => array("username")
|
||||
),
|
||||
"fkey" => array(
|
||||
"fk_domain_admin_acl" => array(
|
||||
"col" => "username",
|
||||
"ref" => "domain_admins.username",
|
||||
"delete" => "CASCADE",
|
||||
"update" => "NO ACTION"
|
||||
)
|
||||
)
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"alias_domain" => array(
|
||||
"cols" => array(
|
||||
"alias_domain" => "VARCHAR(255) NOT NULL",
|
||||
@@ -950,8 +973,9 @@ DELIMITER ;';
|
||||
'msg' => 'db_init_complete'
|
||||
);
|
||||
|
||||
// Fix user_acl
|
||||
// Fix ACL
|
||||
$stmt = $pdo->query("INSERT INTO `user_acl` (`username`) SELECT `username` FROM `mailbox` WHERE `kind` = '' AND NOT EXISTS (SELECT `username` FROM `user_acl`);");
|
||||
$stmt = $pdo->query("INSERT INTO `da_acl` (`username`) SELECT DISTINCT `username` FROM `domain_admins` WHERE `username` != 'admin' AND NOT EXISTS (SELECT `username` FROM `da_acl`);");
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
|
@@ -124,6 +124,7 @@ if (isset($_GET['lang']) && in_array($_GET['lang'], $AVAILABLE_LANGUAGES)) {
|
||||
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.acl.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.address_rewriting.inc.php';
|
||||
@@ -141,6 +142,6 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/init_db.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/triggers.inc.php';
|
||||
init_db_schema();
|
||||
if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
set_acl();
|
||||
acl('to_session');
|
||||
}
|
||||
$UI_TEXTS = customize('get', 'ui_texts');
|
||||
|
@@ -40,7 +40,7 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['acl']['login_as'] == "1") {
|
||||
if (isset($_GET["duallogin"])) {
|
||||
$duallogin = html_entity_decode(rawurldecode($_GET["duallogin"]));
|
||||
if (filter_var($duallogin, FILTER_VALIDATE_EMAIL)) {
|
||||
|
Reference in New Issue
Block a user