From 805634f9a94529a2c611100aed22f5c0b2d11b34 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 3 Apr 2025 10:19:30 +0200 Subject: [PATCH] Fix sasl_logs --- data/conf/dovecot/auth/mailcowauth.php | 15 ++++--- data/conf/dovecot/auth/passwd-verify.lua | 9 ++-- data/web/inc/functions.auth.inc.php | 50 ++++++++++++++-------- data/web/inc/functions.inc.php | 28 ++++++++++++ data/web/js/site/user.js | 6 --- data/web/templates/user/tab-user-auth.twig | 3 +- 6 files changed, 74 insertions(+), 37 deletions(-) diff --git a/data/conf/dovecot/auth/mailcowauth.php b/data/conf/dovecot/auth/mailcowauth.php index fc17df724..667419c57 100644 --- a/data/conf/dovecot/auth/mailcowauth.php +++ b/data/conf/dovecot/auth/mailcowauth.php @@ -69,29 +69,34 @@ require_once 'functions.acl.inc.php'; $isSOGoRequest = $post['real_rip'] == getenv('IPV4_NETWORK') . '.248'; $result = false; -$protocol = $post['protocol']; if ($isSOGoRequest) { - $protocol = null; // This is a SOGo Auth request. First check for SSO password. $sogo_sso_pass = file_get_contents("/etc/sogo-sso/sogo-sso.pass"); if ($sogo_sso_pass === $post['password']){ error_log('MAILCOWAUTH: SOGo SSO auth for user ' . $post['username']); + set_sasl_log($post['username'], $post['real_rip'], "SOGO"); $result = true; } } if ($result === false){ - $result = apppass_login($post['username'], $post['password'], $protocol, array( + $result = apppass_login($post['username'], $post['password'], array($post['service'] => true), array( 'is_internal' => true, 'remote_addr' => $post['real_rip'] )); - if ($result) error_log('MAILCOWAUTH: App auth for user ' . $post['username']); + if ($result) { + error_log('MAILCOWAUTH: App auth for user ' . $post['username']); + set_sasl_log($post['username'], $post['real_rip'], $post['service']); + } } if ($result === false){ // Init Identity Provider $iam_provider = identity_provider('init'); $iam_settings = identity_provider('get'); $result = user_login($post['username'], $post['password'], array('is_internal' => true)); - if ($result) error_log('MAILCOWAUTH: User auth for user ' . $post['username']); + if ($result) { + error_log('MAILCOWAUTH: User auth for user ' . $post['username']); + set_sasl_log($post['username'], $post['real_rip'], $post['service']); + } } if ($result) { diff --git a/data/conf/dovecot/auth/passwd-verify.lua b/data/conf/dovecot/auth/passwd-verify.lua index cb2e928d0..a6cb988d7 100644 --- a/data/conf/dovecot/auth/passwd-verify.lua +++ b/data/conf/dovecot/auth/passwd-verify.lua @@ -12,12 +12,11 @@ function auth_password_verify(request, password) username = request.user, password = password, real_rip = request.real_rip, - protocol = {} + service = request.service } - req.protocol[request.service] = true local req_json = json.encode(req) - local res = {} - + local res = {} + local b, c = https.request { method = "POST", url = "https://nginx:9082", @@ -33,7 +32,7 @@ function auth_password_verify(request, password) if api_response.success == true then return dovecot.auth.PASSDB_RESULT_OK, "" end - + return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate" end diff --git a/data/web/inc/functions.auth.inc.php b/data/web/inc/functions.auth.inc.php index f432c3834..30d5943c4 100644 --- a/data/web/inc/functions.auth.inc.php +++ b/data/web/inc/functions.auth.inc.php @@ -9,25 +9,51 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) { // Try validate admin if (!isset($role) || $role == "admin") { $result = admin_login($user, $pass); - if ($result !== false) return $result; + if ($result !== false){ + return $result; + } } // Try validate domain admin if (!isset($role) || $role == "domain_admin") { $result = domainadmin_login($user, $pass); - if ($result !== false) return $result; + if ($result !== false) { + return $result; + } } // Try validate user if (!isset($role) || $role == "user") { $result = user_login($user, $pass); - if ($result !== false) return $result; + if ($result !== false) { + if ($app_passwd_data['eas'] === true) { + $service = 'EAS'; + } elseif ($app_passwd_data['dav'] === true) { + $service = 'DAV'; + } else { + $service = 'MAILCOWUI'; + } + $real_rip = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']); + set_sasl_log($user, $real_rip, $service); + return $result; + } } // Try validate app password if (!isset($role) || $role == "app") { $result = apppass_login($user, $pass, $app_passwd_data); - if ($result !== false) return $result; + if ($result !== false) { + if ($app_passwd_data['eas'] === true) { + $service = 'EAS'; + } elseif ($app_passwd_data['dav'] === true) { + $service = 'DAV'; + } else { + $service = 'NONE'; + } + $real_rip = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']); + set_sasl_log($user, $real_rip, $service, $pass); + return $result; + } } // skip log and only return false if it's an internal request @@ -415,21 +441,7 @@ function apppass_login($user, $pass, $app_passwd_data, $extra = null){ // verify password if (verify_hash($row['password'], $pass) !== false) { - if ($is_internal){ - $remote_addr = $extra['remote_addr']; - } else { - $remote_addr = ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR']); - } - - $service = strtoupper($is_app_passwd); - $stmt = $pdo->prepare("REPLACE INTO sasl_log (`service`, `app_password`, `username`, `real_rip`) VALUES (:service, :app_id, :username, :remote_addr)"); - $stmt->execute(array( - ':service' => $service, - ':app_id' => $row['app_passwd_id'], - ':username' => $user, - ':remote_addr' => $remote_addr - )); - + $_SESSION['app_passwd_id'] = $row['app_passwd_id']; unset($_SESSION['ldelay']); return "user"; } diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 6a70eb6e3..49e26b978 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -350,6 +350,34 @@ function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) { } } +function set_sasl_log($username, $real_rip, $service){ + global $pdo; + + try { + if (!empty($_SESSION['app_passwd_id'])) { + $app_password = $_SESSION['app_passwd_id']; + } else { + $app_password = 0; + } + + $stmt = $pdo->prepare('REPLACE INTO `sasl_log` (`username`, `real_rip`, `service`, `app_password`) VALUES (:username, :real_rip, :service, :app_password)'); + $stmt->execute(array( + ':username' => $username, + ':real_rip' => $real_rip, + ':service' => $service, + ':app_password' => $app_password + )); + } catch (PDOException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_data_log), + 'msg' => array('mysql_error', $e) + ); + return false; + } + + return true; +} function flush_memcached() { try { $m = new Memcached(); diff --git a/data/web/js/site/user.js b/data/web/js/site/user.js index 8f64d4e20..678e23b19 100644 --- a/data/web/js/site/user.js +++ b/data/web/js/site/user.js @@ -90,13 +90,7 @@ jQuery(function($){ console.log('error reading last logins'); }, success: function (data) { - $('.last-ui-login').html(''); $('.last-sasl-login').html(''); - if (data.ui.time) { - $('.last-ui-login').html(' ' + lang.last_ui_login + ': ' + unix_time_format(data.ui.time)); - } else { - $('.last-ui-login').text(lang.no_last_login); - } if (data.sasl) { $('.last-sasl-login').append('