diff --git a/data/web/admin.php b/data/web/admin.php
index 1a84d410..6347cd7e 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -24,6 +24,7 @@ $tfa_data = get_tfa();
SOGo
Fail2ban
Rspamd
+ Autodiscover
@@ -469,6 +470,24 @@ XYZ
+
+
time(),
+ "ua" => $_SERVER['HTTP_USER_AGENT'],
+ "user" => "none",
+ "service" => "Error: must be authenticated"
+ )
+ );
+ $redis->lPush('AUTODISCOVER_LOG', $json);
+ $redis->lTrim('AUTODISCOVER_LOG', 0, 100);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
header('WWW-Authenticate: Basic realm=""');
header('HTTP/1.0 401 Unauthorized');
exit(0);
@@ -56,6 +75,25 @@ else {
time(),
+ "ua" => $_SERVER['HTTP_USER_AGENT'],
+ "user" => $_SERVER['PHP_AUTH_USER'],
+ "service" => "Error: invalid or missing request data"
+ )
+ );
+ $redis->lPush('AUTODISCOVER_LOG', $json);
+ $redis->lTrim('AUTODISCOVER_LOG', 0, 100);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
list($usec, $sec) = explode(' ', microtime());
?>
@@ -91,7 +129,25 @@ else {
else {
$displayname = $email;
}
-
+ try {
+ $json = json_encode(
+ array(
+ "time" => time(),
+ "ua" => $_SERVER['HTTP_USER_AGENT'],
+ "user" => $_SERVER['PHP_AUTH_USER'],
+ "service" => $autodiscover_config['autodiscoverType']
+ )
+ );
+ $redis->lPush('AUTODISCOVER_LOG', $json);
+ $redis->lTrim('AUTODISCOVER_LOG', 0, 100);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
if ($autodiscover_config['autodiscoverType'] == 'imap') {
?>
diff --git a/data/web/inc/functions.autoconfiguration.inc.php b/data/web/inc/functions.autoconfiguration.inc.php
new file mode 100644
index 00000000..772475c7
--- /dev/null
+++ b/data/web/inc/functions.autoconfiguration.inc.php
@@ -0,0 +1,119 @@
+ 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ switch ($_type) {
+ case 'autodiscover':
+ $objects = (array)$_data['object'];
+ foreach ($objects as $object) {
+ if (is_valid_domain_name($object) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+ $exclude_regex = (isset($_data['exclude_regex'])) ? $_data['exclude_regex'] : null;
+ $exclude_regex = (isset($_data['exclude_regex'])) ? $_data['exclude_regex'] : null;
+ try {
+ $stmt = $pdo->prepare("SELECT COUNT(`domain`) AS `domain_c` FROM `autodiscover`
+ WHERE `domain` = :domain");
+ $stmt->execute(array(':domain' => $object));
+ $num_results = $stmt->fetchColumn();
+ if ($num_results > 0) {
+ $stmt = $pdo->prepare("SELECT COUNT(`domain`) AS `domain_c` FROM `autodiscover`
+ WHERE `domain` = :domain");
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ return false;
+ }
+ }
+ elseif (filter_var($object, FILTER_VALIDATE_EMAIL) === true && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars(implode(', ', $objects)))
+ );
+ break;
+ }
+ break;
+ case 'get':
+ switch ($_type) {
+ case 'autodiscover':
+ $autodiscover = array();
+ if (is_valid_domain_name($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+ try {
+ $stmt = $pdo->prepare("SELECT * FROM `autodiscover`
+ WHERE `domain` = :domain");
+ $stmt->execute(array(':domain' => $_data));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $autodiscover['mailbox'] = $row['mailbox'];
+ $autodiscover['domain'] = $row['domain'];
+ $autodiscover['service'] = $row['service'];
+ $autodiscover['exclude_regex'] = $row['exclude_regex'];
+ $autodiscover['created'] = $row['created'];
+ $autodiscover['modified'] = $row['modified'];
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ return false;
+ }
+ }
+ elseif (filter_var($_data, FILTER_VALIDATE_EMAIL) === true && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+ try {
+ $stmt = $pdo->prepare("SELECT * FROM `autodiscover`
+ WHERE `mailbox` = :mailbox");
+ $stmt->execute(array(':mailbox' => $_data));
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ while($row = array_shift($rows)) {
+ $autodiscover['mailbox'] = $row['mailbox'];
+ $autodiscover['domain'] = $row['domain'];
+ $autodiscover['service'] = $row['service'];
+ $autodiscover['exclude_regex'] = $row['exclude_regex'];
+ $autodiscover['created'] = $row['created'];
+ $autodiscover['modified'] = $row['modified'];
+ }
+ }
+ catch(PDOException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'MySQL: '.$e
+ );
+ return false;
+ }
+ }
+ return $autodiscover;
+ break;
+ }
+ break;
+ case 'reset':
+ switch ($_type) {
+ case 'autodiscover':
+ if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
+ return false;
+ }
+ break;
+ }
+ break;
+ }
+}
+$miau = "Microsoft Office/15.0 (Windows NT 5.1; macOS Outlook 16.0.4734; Pro)";
+preg_match("/^((?!.*Mac|.*emClient).)*(Outlook|Office).+1[5-9].*/i", $miau, $output_array);
+if (empty($output_array)) {
+ echo "imap";
+}
\ No newline at end of file
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index 79f3c6dc..817b9c71 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -900,6 +900,14 @@ function get_logs($container, $lines = 100) {
return $data_array;
}
}
+ if ($container == "autodiscover-mailcow") {
+ if ($data = $redis->lRange('AUTODISCOVER_LOG', 0, $lines)) {
+ foreach ($data as $json_line) {
+ $data_array[] = json_decode($json_line, true);
+ }
+ return $data_array;
+ }
+ }
if ($container == "rspamd-history") {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL,"http://rspamd-mailcow:11334/history");
diff --git a/data/web/js/admin.js b/data/web/js/admin.js
index 7628da82..c6b3b22c 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -124,6 +124,10 @@ jQuery(function($){
e.preventDefault();
draw_postfix_logs();
});
+ $("#refresh_autodiscover_log").on('click', function(e) {
+ e.preventDefault();
+ draw_autodiscover_logs();
+ });
$("#refresh_dovecot_log").on('click', function(e) {
e.preventDefault();
draw_dovecot_logs();
@@ -192,6 +196,52 @@ jQuery(function($){
}
});
}
+ function draw_autodiscover_logs() {
+ ft_autodiscover_logs = FooTable.init('#autodiscover_log', {
+ "columns": [
+ {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
+ {"name":"ua","title":"User-Agent","style":{"min-width":"200px"}},
+ {"name":"user","title":"Username","style":{"min-width":"200px"}},
+ {"name":"service","title":"Service"},
+ ],
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/logs/autodiscover/100',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw autodiscover log table');
+ },
+ success: function (data) {
+ $.each(data, function (i, item) {
+ item.ua = '' + item.ua + '';
+ if (item.service == "activesync") {
+ item.service = 'ActiveSync';
+ }
+ else if (item.service == "imap") {
+ item.service = 'IMAP, SMTP, Cal-/CardDAV';
+ }
+ else {
+ item.service = '' + item.service + '';
+ }
+ });
+ }
+ }),
+ "empty": lang.empty,
+ "paging": {
+ "enabled": true,
+ "limit": 5,
+ "size": log_pagination_size
+ },
+ "filtering": {
+ "enabled": true,
+ "position": "left",
+ "placeholder": lang.filter_table
+ },
+ "sorting": {
+ "enabled": true
+ }
+ });
+ }
function draw_fail2ban_logs() {
ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
"columns": [
@@ -637,6 +687,7 @@ jQuery(function($){
});
}
draw_postfix_logs();
+ draw_autodiscover_logs();
draw_dovecot_logs();
draw_sogo_logs();
draw_fail2ban_logs();
diff --git a/data/web/json_api.php b/data/web/json_api.php
index ec7899c7..167567b5 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -768,6 +768,20 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
else {
echo '{}';
}
+ case "autodiscover":
+ if (isset($extra) && !empty($extra)) {
+ $extra = intval($extra);
+ $logs = get_logs('autodiscover-mailcow', $extra);
+ }
+ else {
+ $logs = get_logs('autodiscover-mailcow', -1);
+ }
+ if (isset($logs) && !empty($logs)) {
+ echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
+ else {
+ echo '{}';
+ }
break;
case "sogo":
if (isset($extra) && !empty($extra)) {