[Web] Show users the last known connections for SASL authentication
[Web] Feature: Log SASL authentication
This commit is contained in:
@@ -251,20 +251,60 @@ function password_check($password1, $password2) {
|
||||
|
||||
return true;
|
||||
}
|
||||
function last_login($user) {
|
||||
function last_login($action, $username) {
|
||||
global $pdo;
|
||||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
||||
AND JSON_EXTRACT(`call`, "$[1]") = :user
|
||||
AND `type` = "success" ORDER BY `time` DESC LIMIT 1');
|
||||
$stmt->execute(array(':user' => $user));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($row)) {
|
||||
return $row;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
switch ($action) {
|
||||
case 'get':
|
||||
if (filter_var($username, FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
|
||||
$stmt = $pdo->prepare('SELECT `real_rip`, MAX(`datetime`) as `datetime`, `service` FROM `sasl_logs`
|
||||
WHERE `username` = :username
|
||||
AND `success` = 1
|
||||
GROUP BY `real_rip`, `service`
|
||||
ORDER BY `datetime` DESC
|
||||
LIMIT 5;');
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$sasl = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($sasl as $k => $v) {
|
||||
if (!filter_var($sasl[$k]['real_rip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$sasl[$k]['real_rip'] = 'Web/EAS/Internal (' . $sasl[$k]['real_rip'] . ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$sasl = array();
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $username == $_SESSION['mailcow_cc_username']) {
|
||||
$stmt = $pdo->prepare('SELECT `remote`, `time` FROM `logs`
|
||||
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
||||
AND JSON_EXTRACT(`call`, "$[1]") = :username
|
||||
AND `type` = "success" ORDER BY `time` DESC LIMIT 1 OFFSET 1');
|
||||
$stmt->execute(array(':username' => $username));
|
||||
$ui = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
else {
|
||||
$ui = array();
|
||||
}
|
||||
|
||||
return array('ui' => $ui, 'sasl' => $sasl);
|
||||
break;
|
||||
case 'reset':
|
||||
if (filter_var($username, FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
|
||||
$stmt = $pdo->prepare('DELETE FROM `sasl_logs`
|
||||
WHERE `username` = :username
|
||||
AND `success` = 1;');
|
||||
$stmt->execute(array(':username' => $username));
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $username == $_SESSION['mailcow_cc_username']) {
|
||||
$stmt = $pdo->prepare('DELETE FROM `logs`
|
||||
WHERE JSON_EXTRACT(`call`, "$[0]") = "check_login"
|
||||
AND JSON_EXTRACT(`call`, "$[1]") = :username
|
||||
AND `type` = "success"');
|
||||
$stmt->execute(array(':username' => $username));
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
function flush_memcached() {
|
||||
try {
|
||||
@@ -1862,6 +1902,26 @@ function get_logs($application, $lines = false) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
if ($application == "sasl") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `sasl_logs` ORDER BY `id` DESC LIMIT :from, :to");
|
||||
$stmt->execute(array(
|
||||
':from' => $from - 1,
|
||||
':to' => $to
|
||||
));
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
else {
|
||||
$stmt = $pdo->prepare("SELECT * FROM `sasl_logs` ORDER BY `id` DESC LIMIT :lines");
|
||||
$stmt->execute(array(
|
||||
':lines' => $lines + 1,
|
||||
));
|
||||
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
if (is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
// Redis
|
||||
if ($application == "dovecot-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
|
@@ -3503,18 +3503,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
$mailboxdata = array();
|
||||
$last_imap_login = $redis->Get('last-login/imap/' . $_data);
|
||||
$last_smtp_login = $redis->Get('last-login/smtp/' . $_data);
|
||||
$last_pop3_login = $redis->Get('last-login/pop3/' . $_data);
|
||||
if ($last_imap_login === false || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_imap_login = '0';
|
||||
}
|
||||
if ($last_smtp_login === false || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_smtp_login = '0';
|
||||
}
|
||||
if ($last_pop3_login === false || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_pop3_login = '0';
|
||||
}
|
||||
if (preg_match('/y|yes/i', getenv('MASTER'))) {
|
||||
$stmt = $pdo->prepare("SELECT
|
||||
`domain`.`backupmx`,
|
||||
@@ -3575,10 +3563,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$mailboxdata['quota_used'] = intval($row['bytes']);
|
||||
$mailboxdata['percent_in_use'] = ($row['quota'] == 0) ? '- ' : round((intval($row['bytes']) / intval($row['quota'])) * 100);
|
||||
|
||||
$mailboxdata['last_imap_login'] = $last_imap_login;
|
||||
$mailboxdata['last_smtp_login'] = $last_smtp_login;
|
||||
$mailboxdata['last_pop3_login'] = $last_pop3_login;
|
||||
|
||||
if ($mailboxdata['percent_in_use'] === '- ') {
|
||||
$mailboxdata['percent_class'] = "info";
|
||||
}
|
||||
@@ -3592,11 +3576,43 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$mailboxdata['percent_class'] = "success";
|
||||
}
|
||||
|
||||
// Determine last logins
|
||||
$stmt = $pdo->prepare("SELECT MAX(`datetime`) AS `datetime`, `service` FROM `sasl_logs`
|
||||
WHERE `username` = :mailbox
|
||||
AND `success` = 1
|
||||
GROUP BY `service` DESC");
|
||||
$stmt->execute(array(':mailbox' => $_data));
|
||||
$SaslLogsData = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
foreach ($SaslLogsData as $SaslLogs) {
|
||||
if ($SaslLogs['service'] == 'imap') {
|
||||
$last_imap_login = strtotime($SaslLogs['datetime']);
|
||||
}
|
||||
else if ($SaslLogs['service'] == 'smtp') {
|
||||
$last_smtp_login = strtotime($SaslLogs['datetime']);
|
||||
}
|
||||
else if ($SaslLogs['service'] == 'pop3') {
|
||||
$last_pop3_login = strtotime($SaslLogs['datetime']);
|
||||
}
|
||||
}
|
||||
if (!isset($last_imap_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_imap_login = 0;
|
||||
}
|
||||
if (!isset($last_smtp_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_smtp_login = 0;
|
||||
}
|
||||
if (!isset($last_pop3_login) || $GLOBALS['SHOW_LAST_LOGIN'] === false) {
|
||||
$last_pop3_login = 0;
|
||||
}
|
||||
$mailboxdata['last_imap_login'] = $last_imap_login;
|
||||
$mailboxdata['last_smtp_login'] = $last_smtp_login;
|
||||
$mailboxdata['last_pop3_login'] = $last_pop3_login;
|
||||
|
||||
if (!isset($_extra) || $_extra != 'reduced') {
|
||||
$rl = ratelimit('get', 'mailbox', $_data);
|
||||
$stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM `domain` WHERE `domain` = :domain");
|
||||
$stmt->execute(array(':domain' => $row['domain']));
|
||||
$DomainQuota = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`active`), 0) AS `pushover_active` FROM `pushover` WHERE `username` = :username AND `active` = 1");
|
||||
$stmt->execute(array(':username' => $_data));
|
||||
$PushoverActive = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
@@ -3,7 +3,7 @@ function init_db_schema() {
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "27052021_2000";
|
||||
$db_version = "03062021_2320";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@@ -510,6 +510,30 @@ function init_db_schema() {
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"sasl_logs" => array(
|
||||
"cols" => array(
|
||||
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||
"success" => "TINYINT(1) NOT NULL DEFAULT '0'",
|
||||
"service" => "VARCHAR(32) NOT NULL DEFAULT ''",
|
||||
"app_password" => "INT",
|
||||
"username" => "VARCHAR(255) NOT NULL",
|
||||
"real_rip" => "VARCHAR(64) NOT NULL",
|
||||
"datetime" => "DATETIME(0) NOT NULL DEFAULT NOW(0)"
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
"" => array("id")
|
||||
),
|
||||
"key" => array(
|
||||
"username" => array("username"),
|
||||
"service" => array("service"),
|
||||
"success" => array("success"),
|
||||
"datetime" => array("datetime"),
|
||||
"real_rip" => array("real_rip")
|
||||
)
|
||||
),
|
||||
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
|
||||
),
|
||||
"quota2" => array(
|
||||
"cols" => array(
|
||||
"username" => "VARCHAR(255) NOT NULL",
|
||||
|
@@ -24,19 +24,16 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
if ($as == "admin") {
|
||||
$_SESSION['mailcow_cc_username'] = $login_user;
|
||||
$_SESSION['mailcow_cc_role'] = "admin";
|
||||
$_SESSION['mailcow_cc_last_login'] = last_login($login_user);
|
||||
header("Location: /admin");
|
||||
}
|
||||
elseif ($as == "domainadmin") {
|
||||
$_SESSION['mailcow_cc_username'] = $login_user;
|
||||
$_SESSION['mailcow_cc_role'] = "domainadmin";
|
||||
$_SESSION['mailcow_cc_last_login'] = last_login($login_user);
|
||||
header("Location: /mailbox");
|
||||
}
|
||||
elseif ($as == "user") {
|
||||
$_SESSION['mailcow_cc_username'] = $login_user;
|
||||
$_SESSION['mailcow_cc_role'] = "user";
|
||||
$_SESSION['mailcow_cc_last_login'] = last_login($login_user);
|
||||
$http_parameters = explode('&', $_SESSION['index_query_string']);
|
||||
unset($_SESSION['index_query_string']);
|
||||
if (in_array('mobileconfig', $http_parameters)) {
|
||||
|
Reference in New Issue
Block a user