mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2025-12-25 07:41:30 +00:00
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password [Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!) [Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes) [Web] Flush memcached after mailbox item changes, fixes #1808 [Web] Fix duplicate IDs, fixes #1792 [Compose] Use SQL sockets [PHP-FPM] Update APCu and Redis libs [Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791 [Web] Fix deletion of spam aliases [Helper] Add "crypt" to backup script [Helper] Override file for external SQL socket (not supported!) [Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
This commit is contained in:
@@ -59,7 +59,7 @@ $(document).ready(function() {
|
||||
});
|
||||
$('#u2f_status_auth').html('<p><span class="glyphicon glyphicon-refresh glyphicon-spin"></span> Initializing, please wait...</p>');
|
||||
$('#ConfirmTFAModal').on('shown.bs.modal', function(){
|
||||
$(this).find('#token').focus();
|
||||
$(this).find('input[name=token]').focus();
|
||||
// If U2F
|
||||
if(document.getElementById("u2f_auth_data") !== null) {
|
||||
$.ajax({
|
||||
@@ -146,7 +146,7 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
// CSRF
|
||||
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form');
|
||||
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('name', 'csrf_token').appendTo('form');
|
||||
if (sessionStorage.scrollTop != "undefined") {
|
||||
$(window).scrollTop(sessionStorage.scrollTop);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
||||
global $DOCKER_TIMEOUT;
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array( 'Content-Type: application/json' ));
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
||||
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
switch($action) {
|
||||
case 'get_id':
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json');
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
@@ -38,7 +41,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
}
|
||||
return false;
|
||||
case 'containers':
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json');
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
@@ -74,7 +77,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
break;
|
||||
case 'info':
|
||||
if (empty($service_name)) {
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json');
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/json');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, 0);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
@@ -82,7 +85,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
else {
|
||||
$container_id = docker('get_id', $service_name);
|
||||
if (ctype_xdigit($container_id)) {
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/json');
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/json');
|
||||
}
|
||||
else {
|
||||
// logger(array('return' => array(
|
||||
@@ -144,7 +147,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
if (!empty($attr1)) {
|
||||
$container_id = docker('get_id', $service_name);
|
||||
if (ctype_xdigit($container_id) && ctype_alnum($attr1)) {
|
||||
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/' . $attr1);
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://dockerapi:443/containers/' . $container_id . '/' . $attr1);
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $DOCKER_TIMEOUT);
|
||||
if (!empty($attr2)) {
|
||||
@@ -158,19 +161,19 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
if ($response === false) {
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
logger(array('return' => array(array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers),
|
||||
'msg' => $err,
|
||||
))));
|
||||
// logger(array('return' => array(array(
|
||||
// 'type' => 'danger',
|
||||
// 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers),
|
||||
// 'msg' => $err,
|
||||
// ))));
|
||||
return $err;
|
||||
}
|
||||
else {
|
||||
curl_close($curl);
|
||||
logger(array('return' => array(array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers),
|
||||
))));
|
||||
// logger(array('return' => array(array(
|
||||
// 'type' => 'success',
|
||||
// 'log' => array(__FUNCTION__, $action, $service_name, $attr1, $attr2, $extra_headers),
|
||||
// ))));
|
||||
if (empty($response)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,17 @@ function last_login($user) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function flush_memcached() {
|
||||
try {
|
||||
$m = new Memcached();
|
||||
$m->addServer('memcached', 11211);
|
||||
$m->flush();
|
||||
}
|
||||
catch ( Exception $e ) {
|
||||
// Dunno
|
||||
}
|
||||
}
|
||||
|
||||
function logger($_data = false) {
|
||||
/*
|
||||
logger() will be called as last function
|
||||
@@ -510,6 +521,7 @@ function update_sogo_static_view() {
|
||||
$stmt = $pdo->query("REPLACE INTO _sogo_static_view SELECT * from sogo_view");
|
||||
$stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');");
|
||||
}
|
||||
flush_memcached();
|
||||
}
|
||||
function edit_user_account($_data) {
|
||||
global $lang;
|
||||
|
||||
@@ -2776,6 +2776,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`mailbox`.`active` AS `active_int`,
|
||||
CASE `mailbox`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
|
||||
`mailbox`.`domain`,
|
||||
`mailbox`.`maildir`,
|
||||
`mailbox`.`quota`,
|
||||
`quota2`.`bytes`,
|
||||
`attributes`,
|
||||
@@ -2806,6 +2807,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$mailboxdata['active'] = $row['active'];
|
||||
$mailboxdata['active_int'] = $row['active_int'];
|
||||
$mailboxdata['domain'] = $row['domain'];
|
||||
$mailboxdata['maildir'] = $row['maildir'];
|
||||
$mailboxdata['quota'] = $row['quota'];
|
||||
$mailboxdata['attributes'] = json_decode($row['attributes'], true);
|
||||
$mailboxdata['quota_used'] = intval($row['bytes']);
|
||||
@@ -3054,6 +3056,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$exec_fields = array('cmd' => 'maildir_cleanup', 'maildir' => $domain);
|
||||
$maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
|
||||
if ($maildir_gc['type'] != 'success') {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'warning',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
|
||||
);
|
||||
}
|
||||
return false;
|
||||
$stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => $domain,
|
||||
@@ -3078,17 +3090,17 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :domain");
|
||||
$stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` LIKE :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` = :domain");
|
||||
$stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` LIKE :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
':domain' => $domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
|
||||
$stmt->execute(array(
|
||||
@@ -3227,6 +3239,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$maildir = mailbox('get', 'mailbox_details', $username)['maildir'];
|
||||
$exec_fields = array('cmd' => 'maildir_cleanup', 'maildir' => $maildir);
|
||||
$maildir_gc = json_decode(docker('post', 'dovecot-mailcow', 'exec', $exec_fields), true);
|
||||
if ($maildir_gc['type'] != 'success') {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'warning',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => 'Could not move maildir to garbage collector: ' . $maildir_gc['msg']
|
||||
);
|
||||
}
|
||||
$stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
|
||||
@@ -3,7 +3,7 @@ function init_db_schema() {
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "01092018_1902";
|
||||
$db_version = "21092018_1902";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
@@ -35,7 +35,7 @@ $hrs = floor($mins / 60);
|
||||
$mins -= $hrs * 60;
|
||||
$offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);
|
||||
|
||||
$dsn = $database_type . ":host=" . $database_host . ";dbname=" . $database_name;
|
||||
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
|
||||
$opt = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
@@ -46,11 +46,20 @@ try {
|
||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
// Stop when SQL connection fails
|
||||
?>
|
||||
<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>Connection to database failed.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
|
||||
<center style='font-family:sans-serif;'>Connection to database failed.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
// Stop when dockerapi is not available
|
||||
if (fsockopen("tcp://dockerapi", 443, $errno, $errstr) === false) {
|
||||
?>
|
||||
<center style='font-family:sans-serif;'>Connection to dockerapi container failed.<br /><br />The following error was reported:<br/><?=$errno;?> - <?=$errstr;?></center>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
function pdo_exception_handler($e) {
|
||||
print_r($e);
|
||||
if ($e instanceof PDOException) {
|
||||
@@ -146,3 +155,4 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||
acl('to_session');
|
||||
}
|
||||
$UI_TEXTS = customize('get', 'ui_texts');
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ This file will be reset on upgrades.
|
||||
|
||||
// SQL database connection variables
|
||||
$database_type = 'mysql';
|
||||
$database_sock = '/var/run/mysqld/mysqld.sock';
|
||||
$database_host = 'mysql';
|
||||
$database_user = getenv('DBUSER');
|
||||
$database_pass = getenv('DBPASS');
|
||||
|
||||
Reference in New Issue
Block a user