git subrepo commit (merge) mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "32243e56"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "e2b4b6f6"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: I51e2016ef5ab88a8b0bdc08551b18f48ceef0aa5
diff --git a/mailcow/src/mailcow-dockerized/data/web/inc/functions.inc.php b/mailcow/src/mailcow-dockerized/data/web/inc/functions.inc.php
index 142a9fe..7ac0af5 100644
--- a/mailcow/src/mailcow-dockerized/data/web/inc/functions.inc.php
+++ b/mailcow/src/mailcow-dockerized/data/web/inc/functions.inc.php
@@ -258,7 +258,7 @@
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`, `app_password` FROM `sasl_log`
+ $stmt = $pdo->prepare('SELECT `real_rip`, MAX(`datetime`) as `datetime`, `service`, `app_password`, MAX(`app_passwd`.`name`) as `app_password_name` FROM `sasl_log`
LEFT OUTER JOIN `app_passwd` on `sasl_log`.`app_password` = `app_passwd`.`id`
WHERE `username` = :username
AND HOUR(TIMEDIFF(NOW(), `datetime`)) < :sasl_limit_days
@@ -807,10 +807,11 @@
}
return false;
}
-function check_login($user, $pass) {
+function check_login($user, $pass, $app_passwd_data = false) {
global $pdo;
global $redis;
global $imap_server;
+
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -819,6 +820,8 @@
);
return false;
}
+
+ // Validate admin
$user = strtolower(trim($user));
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
WHERE `superadmin` = '1'
@@ -854,6 +857,8 @@
}
}
}
+
+ // Validate domain admin
$stmt = $pdo->prepare("SELECT `password` FROM `admin`
WHERE `superadmin` = '0'
AND `active`='1'
@@ -888,6 +893,8 @@
}
}
}
+
+ // Validate mailbox user
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
INNER JOIN domain on mailbox.domain = domain.domain
WHERE `kind` NOT REGEXP 'location|thing|group'
@@ -896,6 +903,32 @@
AND `username` = :user");
$stmt->execute(array(':user' => $user));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ if ($app_passwd_data['eas'] === true) {
+ $stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd`
+ INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox`
+ INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
+ WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group'
+ AND `mailbox`.`active` = '1'
+ AND `domain`.`active` = '1'
+ AND `app_passwd`.`active` = '1'
+ AND `app_passwd`.`eas_access` = '1'
+ AND `app_passwd`.`mailbox` = :user");
+ $stmt->execute(array(':user' => $user));
+ $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC));
+ }
+ elseif ($app_passwd_data['dav'] === true) {
+ $stmt = $pdo->prepare("SELECT `app_passwd`.`password` as `password`, `app_passwd`.`id` as `app_passwd_id` FROM `app_passwd`
+ INNER JOIN `mailbox` ON `mailbox`.`username` = `app_passwd`.`mailbox`
+ INNER JOIN `domain` ON `mailbox`.`domain` = `domain`.`domain`
+ WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group'
+ AND `mailbox`.`active` = '1'
+ AND `domain`.`active` = '1'
+ AND `app_passwd`.`active` = '1'
+ AND `app_passwd`.`dav_access` = '1'
+ AND `app_passwd`.`mailbox` = :user");
+ $stmt->execute(array(':user' => $user));
+ $rows = array_merge($rows, $stmt->fetchAll(PDO::FETCH_ASSOC));
+ }
foreach ($rows as $row) {
if (verify_hash($row['password'], $pass) !== false) {
unset($_SESSION['ldelay']);
@@ -904,9 +937,20 @@
'log' => array(__FUNCTION__, $user, '*'),
'msg' => array('logged_in_as', $user)
);
+ if ($app_passwd_data['eas'] === true || $app_passwd_data['dav'] === true) {
+ $service = ($app_passwd_data['eas'] === true) ? 'EAS' : 'DAV';
+ $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' => ($_SERVER['HTTP_X_REAL_IP'] ?? $_SERVER['REMOTE_ADDR'])
+ ));
+ }
return "user";
}
}
+
if (!isset($_SESSION['ldelay'])) {
$_SESSION['ldelay'] = "0";
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
@@ -917,11 +961,13 @@
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
}
+
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $user, '*'),
'msg' => 'login_failed'
);
+
sleep($_SESSION['ldelay']);
return false;
}
@@ -1222,8 +1268,8 @@
case "totp":
$key_id = (!isset($_data["key_id"])) ? 'unidentified' : $_data["key_id"];
if ($tfa->verifyCode($_POST['totp_secret'], $_POST['totp_confirm_token']) === true) {
- $stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
- $stmt->execute(array(':username' => $username));
+ //$stmt = $pdo->prepare("DELETE FROM `tfa` WHERE `username` = :username");
+ //$stmt->execute(array(':username' => $username));
$stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `key_id`, `authmech`, `secret`, `active`) VALUES (?, ?, 'totp', ?, '1')");
$stmt->execute(array($username, $key_id, $_POST['totp_secret']));
$_SESSION['return'][] = array(
@@ -1610,15 +1656,17 @@
AND `authmech` = 'totp'
AND `active`='1'");
$stmt->execute(array(':username' => $username));
- $row = $stmt->fetch(PDO::FETCH_ASSOC);
- if ($tfa->verifyCode($row['secret'], $_POST['token']) === true) {
- $_SESSION['tfa_id'] = $row['id'];
- $_SESSION['return'][] = array(
- 'type' => 'success',
- 'log' => array(__FUNCTION__, $username, '*'),
- 'msg' => 'verified_totp_login'
- );
- return true;
+ $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($rows as $row) {
+ if ($tfa->verifyCode($row['secret'], $_POST['token']) === true) {
+ $_SESSION['tfa_id'] = $row['id'];
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $username, '*'),
+ 'msg' => 'verified_totp_login'
+ );
+ return true;
+ }
}
$_SESSION['return'][] = array(
'type' => 'danger',