From 9c37cd76e5d11eb7150d4afbdf39db1bc461a468 Mon Sep 17 00:00:00 2001 From: andryyy Date: Mon, 2 Oct 2017 21:47:31 +0200 Subject: [PATCH] [Web] Autodiscover logs --- data/web/admin.php | 19 +++ data/web/autodiscover.php | 60 ++++++++- .../inc/functions.autoconfiguration.inc.php | 119 ++++++++++++++++++ data/web/inc/functions.inc.php | 8 ++ data/web/js/admin.js | 51 ++++++++ data/web/json_api.php | 14 +++ 6 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 data/web/inc/functions.autoconfiguration.inc.php 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 +
    +
    +
    Autodiscover +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + 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)) {