mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-01-30 09:07:19 +00:00
Merge pull request #7022 from mailcow/feat/eas-dav-access
[Web] Allow admins to limit EAS and DAV access for mailbox users
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
<?php
|
||||
function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
||||
function check_login($user, $pass, $extra = null) {
|
||||
global $pdo;
|
||||
global $redis;
|
||||
|
||||
$is_internal = $extra['is_internal'];
|
||||
$role = $extra['role'];
|
||||
$extra['service'] = !isset($extra['service']) ? 'NONE' : $extra['service'];
|
||||
|
||||
// Try validate admin
|
||||
if (!isset($role) || $role == "admin") {
|
||||
@@ -25,34 +26,20 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
||||
|
||||
// Try validate app password
|
||||
if (!isset($role) || $role == "app") {
|
||||
$result = apppass_login($user, $pass, $app_passwd_data);
|
||||
$result = apppass_login($user, $pass, $extra);
|
||||
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);
|
||||
set_sasl_log($user, $real_rip, $extra['service'], $pass);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
// Try validate user
|
||||
if (!isset($role) || $role == "user") {
|
||||
$result = user_login($user, $pass);
|
||||
$result = user_login($user, $pass, $extra);
|
||||
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);
|
||||
set_sasl_log($user, $real_rip, $extra['service']);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -193,7 +180,7 @@ function user_login($user, $pass, $extra = null){
|
||||
global $iam_settings;
|
||||
|
||||
$is_internal = $extra['is_internal'];
|
||||
$service = $extra['service'];
|
||||
$extra['service'] = !isset($extra['service']) ? 'NONE' : $extra['service'];
|
||||
|
||||
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
|
||||
if (!$is_internal){
|
||||
@@ -236,10 +223,10 @@ function user_login($user, $pass, $extra = null){
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!empty($row)) {
|
||||
// check if user has access to service (imap, smtp, pop3, sieve) if service is set
|
||||
// check if user has access to service (imap, smtp, pop3, sieve, dav, eas) if service is set
|
||||
$row['attributes'] = json_decode($row['attributes'], true);
|
||||
if (isset($service)) {
|
||||
$key = strtolower($service) . "_access";
|
||||
if ($extra['service'] != 'NONE') {
|
||||
$key = strtolower($extra['service']) . "_access";
|
||||
if (isset($row['attributes'][$key]) && $row['attributes'][$key] != '1') {
|
||||
return false;
|
||||
}
|
||||
@@ -253,8 +240,8 @@ function user_login($user, $pass, $extra = null){
|
||||
|
||||
// check if user has access to service (imap, smtp, pop3, sieve) if service is set
|
||||
$row['attributes'] = json_decode($row['attributes'], true);
|
||||
if (isset($service)) {
|
||||
$key = strtolower($service) . "_access";
|
||||
if ($extra['service'] != 'NONE') {
|
||||
$key = strtolower($extra['service']) . "_access";
|
||||
if (isset($row['attributes'][$key]) && $row['attributes'][$key] != '1') {
|
||||
return false;
|
||||
}
|
||||
@@ -408,7 +395,7 @@ function user_login($user, $pass, $extra = null){
|
||||
|
||||
return false;
|
||||
}
|
||||
function apppass_login($user, $pass, $app_passwd_data, $extra = null){
|
||||
function apppass_login($user, $pass, $extra = null){
|
||||
global $pdo;
|
||||
|
||||
$is_internal = $extra['is_internal'];
|
||||
@@ -424,20 +411,8 @@ function apppass_login($user, $pass, $app_passwd_data, $extra = null){
|
||||
return false;
|
||||
}
|
||||
|
||||
$protocol = false;
|
||||
if ($app_passwd_data['eas']){
|
||||
$protocol = 'eas';
|
||||
} else if ($app_passwd_data['dav']){
|
||||
$protocol = 'dav';
|
||||
} else if ($app_passwd_data['smtp']){
|
||||
$protocol = 'smtp';
|
||||
} else if ($app_passwd_data['imap']){
|
||||
$protocol = 'imap';
|
||||
} else if ($app_passwd_data['sieve']){
|
||||
$protocol = 'sieve';
|
||||
} else if ($app_passwd_data['pop3']){
|
||||
$protocol = 'pop3';
|
||||
} else if (!$is_internal) {
|
||||
$extra['service'] = !isset($extra['service']) ? 'NONE' : $extra['service'];
|
||||
if (!$is_internal && $extra['service'] == 'NONE') {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -458,7 +433,7 @@ function apppass_login($user, $pass, $app_passwd_data, $extra = null){
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
if ($protocol && $row[$protocol . '_access'] != '1'){
|
||||
if ($extra['service'] != 'NONE' && $row[strtolower($extra['service']) . '_access'] != '1'){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1075,6 +1075,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
$active = (isset($_data['active'])) ? intval($_data['active']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['active']);
|
||||
$force_pw_update = (isset($_data['force_pw_update'])) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||
@@ -1085,6 +1087,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||
$smtp_access = (isset($_data['smtp_access'])) ? intval($_data['smtp_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||
$sieve_access = (isset($_data['sieve_access'])) ? intval($_data['sieve_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||
$eas_access = (isset($_data['eas_access'])) ? intval($_data['eas_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['eas_access']);
|
||||
$dav_access = (isset($_data['dav_access'])) ? intval($_data['dav_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['dav_access']);
|
||||
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
|
||||
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
||||
$quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
||||
@@ -1103,6 +1107,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
'pop3_access' => strval($pop3_access),
|
||||
'smtp_access' => strval($smtp_access),
|
||||
'sieve_access' => strval($sieve_access),
|
||||
'eas_access' => strval($eas_access),
|
||||
'dav_access' => strval($dav_access),
|
||||
'relayhost' => strval($relayhost),
|
||||
'passwd_update' => time(),
|
||||
'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
|
||||
@@ -1721,12 +1727,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
$attr['imap_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
|
||||
$attr['pop3_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']);
|
||||
$attr['smtp_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['smtp_access']);
|
||||
$attr['sieve_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['sieve_access']);
|
||||
$attr['eas_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['eas_access']);
|
||||
$attr['dav_access'] = intval($MAILBOX_DEFAULT_ATTRIBUTES['dav_access']);
|
||||
}
|
||||
if (isset($_data['acl'])) {
|
||||
$_data['acl'] = (array)$_data['acl'];
|
||||
@@ -3043,6 +3053,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
|
||||
$_data['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
if (!empty($is_now)) {
|
||||
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
|
||||
@@ -3052,6 +3064,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
(int)$pop3_access = (isset($_data['pop3_access']) && hasACLAccess("protocol_access")) ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
|
||||
(int)$smtp_access = (isset($_data['smtp_access']) && hasACLAccess("protocol_access")) ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
|
||||
(int)$sieve_access = (isset($_data['sieve_access']) && hasACLAccess("protocol_access")) ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
|
||||
(int)$eas_access = (isset($_data['eas_access']) && hasACLAccess("protocol_access")) ? intval($_data['eas_access']) : intval($is_now['attributes']['eas_access']);
|
||||
(int)$dav_access = (isset($_data['dav_access']) && hasACLAccess("protocol_access")) ? intval($_data['dav_access']) : intval($is_now['attributes']['dav_access']);
|
||||
(int)$relayhost = (isset($_data['relayhost']) && hasACLAccess("mailbox_relayhost")) ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
|
||||
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576);
|
||||
$name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
|
||||
@@ -3335,6 +3349,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
|
||||
`attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.eas_access', :eas_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.dav_access', :dav_access),
|
||||
`attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email),
|
||||
`attributes` = JSON_SET(`attributes`, '$.attribute_hash', :attribute_hash)
|
||||
WHERE `username` = :username");
|
||||
@@ -3349,6 +3365,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
':pop3_access' => $pop3_access,
|
||||
':sieve_access' => $sieve_access,
|
||||
':smtp_access' => $smtp_access,
|
||||
':eas_access' => $eas_access,
|
||||
':dav_access' => $dav_access,
|
||||
':recovery_email' => $pw_recovery_email,
|
||||
':relayhost' => $relayhost,
|
||||
':username' => $username,
|
||||
@@ -3731,6 +3749,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$attr['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['smtp_access'] = (in_array('smtp', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['sieve_access'] = (in_array('sieve', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['eas_access'] = (in_array('eas', $_data['protocol_access'])) ? 1 : 0;
|
||||
$attr['dav_access'] = (in_array('dav', $_data['protocol_access'])) ? 1 : 0;
|
||||
}
|
||||
else {
|
||||
foreach ($is_now as $key => $value){
|
||||
|
||||
@@ -4,7 +4,7 @@ function init_db_schema()
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "10312025_0525";
|
||||
$db_version = "28012026_1000";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@@ -1394,6 +1394,8 @@ function init_db_schema()
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.imap_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.imap_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.pop3_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.pop3_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.smtp_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.smtp_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.eas_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.eas_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.dav_access', \"1\") WHERE JSON_VALUE(`attributes`, '$.dav_access') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.mailbox_format', \"maildir:\") WHERE JSON_VALUE(`attributes`, '$.mailbox_format') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_notification', \"never\") WHERE JSON_VALUE(`attributes`, '$.quarantine_notification') IS NULL;");
|
||||
$pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.quarantine_category', \"reject\") WHERE JSON_VALUE(`attributes`, '$.quarantine_category') IS NULL;");
|
||||
|
||||
@@ -121,7 +121,7 @@ class mailcowPdo extends OAuth2\Storage\Pdo {
|
||||
$this->config['user_table'] = 'mailbox';
|
||||
}
|
||||
public function checkUserCredentials($username, $password) {
|
||||
if (check_login($username, $password) == 'user') {
|
||||
if (check_login($username, $password, array("role" => "user", "service" => "NONE")) == 'user') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -44,7 +44,7 @@ if (isset($_GET["cancel_tfa_login"])) {
|
||||
|
||||
if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
$login_user = strtolower(trim($_POST["login_user"]));
|
||||
$as = check_login($login_user, $_POST["pass_user"], false, array("role" => "admin"));
|
||||
$as = check_login($login_user, $_POST["pass_user"], array("role" => "admin", "service" => "MAILCOWUI"));
|
||||
|
||||
if ($as == "admin") {
|
||||
session_regenerate_id(true);
|
||||
|
||||
@@ -55,7 +55,7 @@ if (isset($_GET["cancel_tfa_login"])) {
|
||||
|
||||
if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
$login_user = strtolower(trim($_POST["login_user"]));
|
||||
$as = check_login($login_user, $_POST["pass_user"], false, array("role" => "domain_admin"));
|
||||
$as = check_login($login_user, $_POST["pass_user"], array("role" => "domain_admin", "service" => "MAILCOWUI"));
|
||||
|
||||
if ($as == "domainadmin") {
|
||||
session_regenerate_id(true);
|
||||
|
||||
@@ -119,7 +119,7 @@ if (isset($_GET["cancel_tfa_login"])) {
|
||||
|
||||
if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
|
||||
$login_user = strtolower(trim($_POST["login_user"]));
|
||||
$as = check_login($login_user, $_POST["pass_user"], false, array("role" => "user"));
|
||||
$as = check_login($login_user, $_POST["pass_user"], array("role" => "user", "service" => "MAILCOWUI"));
|
||||
|
||||
if ($as == "user") {
|
||||
set_user_loggedin_session($login_user);
|
||||
|
||||
@@ -217,6 +217,12 @@ $MAILBOX_DEFAULT_ATTRIBUTES['smtp_access'] = true;
|
||||
// Mailbox has sieve access by default
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['sieve_access'] = true;
|
||||
|
||||
// Mailbox has ActiveSync/EAS access by default
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['eas_access'] = true;
|
||||
|
||||
// Mailbox has CalDAV/CardDAV (DAV) access by default
|
||||
$MAILBOX_DEFAULT_ATTRIBUTES['dav_access'] = true;
|
||||
|
||||
// Mailbox receives notifications about...
|
||||
// "add_header" - mail that was put into the Junk folder
|
||||
// "reject" - mail that was rejected
|
||||
|
||||
Reference in New Issue
Block a user