[Dovecot, Web] Allow SOGo access with app password when imap is disabled; Add sieve to mailbox protocol access restrictions

master
andryyy 2021-10-30 08:03:41 +02:00
parent 51c8d43223
commit 644b1f85d1
No known key found for this signature in database
GPG Key ID: 8EC34FF2794E25EF
6 changed files with 28 additions and 11 deletions

View File

@ -155,9 +155,10 @@ function auth_password_verify(req, pass)
local row = cur:fetch ({}, "a") local row = cur:fetch ({}, "a")
while row do while row do
if req.password_verify(req, row.password, pass) == 1 then if req.password_verify(req, row.password, pass) == 1 then
cur:close()
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip) con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
VALUES ("%s", 0, "%s", "%s")]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip))) VALUES ("%s", 0, "%s", "%s")]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip)))
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
end end
row = cur:fetch (row, "a") row = cur:fetch (row, "a")
@ -166,25 +167,31 @@ function auth_password_verify(req, pass)
-- check against app passwds for imap and smtp -- check against app passwds for imap and smtp
-- app passwords are only available for imap, smtp, sieve and pop3 when using sasl -- app passwords are only available for imap, smtp, sieve and pop3 when using sasl
if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then
local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.imap_access, app_passwd.smtp_access, app_passwd.sieve_access, app_passwd.pop3_access, app_passwd.password FROM app_passwd local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, %s_access AS has_prot_access, app_passwd.password FROM app_passwd
INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox
WHERE mailbox = '%s' WHERE mailbox = '%s'
AND app_passwd.%s_access = '1'
AND app_passwd.active = '1' AND app_passwd.active = '1'
AND mailbox.active = '1' AND mailbox.active = '1'
AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.user), con:escape(req.service), con:escape(req.domain))) AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.service), con:escape(req.user), con:escape(req.domain)))
local row = cur:fetch ({}, "a") local row = cur:fetch ({}, "a")
while row do while row do
if req.password_verify(req, row.password, pass) == 1 then if req.password_verify(req, row.password, pass) == 1 then
cur:close() -- if password is valid and protocol access is 1 OR real_rip matches SOGo, proceed
if tostring(req.real_ip) == "__IPV4_SOGO__" or row.has_prot_access == "1" then
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip) con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip))) VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
end end
end
row = cur:fetch (row, "a") row = cur:fetch (row, "a")
end end
end end
cur:close()
con:close()
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate" return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
-- PoC -- PoC
@ -232,6 +239,7 @@ EOF
sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBNAME__/${DBNAME}/g" /etc/dovecot/lua/passwd-verify.lua sed -i "s/__DBNAME__/${DBNAME}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__IPV4_SOGO__/${IPV4_NETWORK}.248/g" /etc/dovecot/lua/passwd-verify.lua
# Migrate old sieve_after file # Migrate old sieve_after file

View File

@ -42,7 +42,9 @@ foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
$twig->addGlobal($globalVariableName, $globalVariableValue); $twig->addGlobal($globalVariableName, $globalVariableValue);
} }
if (is_array($template_data)) {
echo $twig->render($template, $template_data); echo $twig->render($template, $template_data);
}
if (isset($_SESSION['mailcow_cc_api'])) { if (isset($_SESSION['mailcow_cc_api'])) {
session_regenerate_id(true); session_regenerate_id(true);

View File

@ -962,6 +962,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']); $imap_access = (isset($_data['imap_access'])) ? intval($_data['imap_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['imap_access']);
$pop3_access = (isset($_data['pop3_access'])) ? intval($_data['pop3_access']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['pop3_access']); $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']); $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']);
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0; $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_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']); $quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
@ -975,6 +976,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
'imap_access' => strval($imap_access), 'imap_access' => strval($imap_access),
'pop3_access' => strval($pop3_access), 'pop3_access' => strval($pop3_access),
'smtp_access' => strval($smtp_access), 'smtp_access' => strval($smtp_access),
'sieve_access' => strval($sieve_access),
'relayhost' => strval($relayhost), 'relayhost' => strval($relayhost),
'passwd_update' => time(), 'passwd_update' => time(),
'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']), 'mailbox_format' => strval($MAILBOX_DEFAULT_ATTRIBUTES['mailbox_format']),
@ -2341,6 +2343,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0; $_data['imap_access'] = (in_array('imap', $_data['protocol_access'])) ? 1 : 0;
$_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0; $_data['pop3_access'] = (in_array('pop3', $_data['protocol_access'])) ? 1 : 0;
$_data['smtp_access'] = (in_array('smtp', $_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;
} }
if (!empty($is_now)) { if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active']; $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
@ -2349,6 +2352,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
(int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']); (int)$imap_access = (isset($_data['imap_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['imap_access']) : intval($is_now['attributes']['imap_access']);
(int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']); (int)$pop3_access = (isset($_data['pop3_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['pop3_access']) : intval($is_now['attributes']['pop3_access']);
(int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']); (int)$smtp_access = (isset($_data['smtp_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['smtp_access']) : intval($is_now['attributes']['smtp_access']);
(int)$sieve_access = (isset($_data['sieve_access']) && isset($_SESSION['acl']['protocol_access']) && $_SESSION['acl']['protocol_access'] == "1") ? intval($_data['sieve_access']) : intval($is_now['attributes']['sieve_access']);
(int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']); (int)$relayhost = (isset($_data['relayhost']) && isset($_SESSION['acl']['mailbox_relayhost']) && $_SESSION['acl']['mailbox_relayhost'] == "1") ? intval($_data['relayhost']) : intval($is_now['attributes']['relayhost']);
(int)$quota_m = (isset_has_content($_data['quota'])) ? intval($_data['quota']) : ($is_now['quota'] / 1048576); (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']; $name = (!empty($_data['name'])) ? ltrim(rtrim($_data['name'], '>'), '<') : $is_now['name'];
@ -2614,6 +2618,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update), `attributes` = JSON_SET(`attributes`, '$.force_pw_update', :force_pw_update),
`attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access), `attributes` = JSON_SET(`attributes`, '$.sogo_access', :sogo_access),
`attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access), `attributes` = JSON_SET(`attributes`, '$.imap_access', :imap_access),
`attributes` = JSON_SET(`attributes`, '$.sieve_access', :sieve_access),
`attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access), `attributes` = JSON_SET(`attributes`, '$.pop3_access', :pop3_access),
`attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost), `attributes` = JSON_SET(`attributes`, '$.relayhost', :relayhost),
`attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access) `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access)
@ -2626,6 +2631,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':sogo_access' => $sogo_access, ':sogo_access' => $sogo_access,
':imap_access' => $imap_access, ':imap_access' => $imap_access,
':pop3_access' => $pop3_access, ':pop3_access' => $pop3_access,
':sieve_access' => $sieve_access,
':smtp_access' => $smtp_access, ':smtp_access' => $smtp_access,
':relayhost' => $relayhost, ':relayhost' => $relayhost,
':username' => $username ':username' => $username

View File

@ -506,7 +506,7 @@
"alias": "Alias bearbeiten", "alias": "Alias bearbeiten",
"allow_from_smtp": "Nur folgende IPs für <b>SMTP</b> erlauben", "allow_from_smtp": "Nur folgende IPs für <b>SMTP</b> erlauben",
"allow_from_smtp_info": "Leer lassen, um keine Prüfung durchzuführen.<br>IPv4- sowie IPv6-Adressen und Subnetzwerke.", "allow_from_smtp_info": "Leer lassen, um keine Prüfung durchzuführen.<br>IPv4- sowie IPv6-Adressen und Subnetzwerke.",
"allowed_protocols": "Erlaubte Protokolle", "allowed_protocols": "Erlaubte Protokolle für direkten Zugriff (hat keinen Einfluss auf App-Passwort Protokolle)",
"app_name": "App-Name", "app_name": "App-Name",
"app_passwd": "App-Passwörter", "app_passwd": "App-Passwörter",
"app_passwd_protocols": "Zugelassene Protokolle für App-Passwort", "app_passwd_protocols": "Zugelassene Protokolle für App-Passwort",

View File

@ -705,7 +705,7 @@
"all_domains": "All Domains", "all_domains": "All Domains",
"allow_from_smtp": "Only allow these IPs to use <b>SMTP</b>", "allow_from_smtp": "Only allow these IPs to use <b>SMTP</b>",
"allow_from_smtp_info": "Leave empty to allow all senders.<br>IPv4/IPv6 addresses and networks.", "allow_from_smtp_info": "Leave empty to allow all senders.<br>IPv4/IPv6 addresses and networks.",
"allowed_protocols": "Allowed protocols", "allowed_protocols": "Allowed protocols for direct user access (does not affect app password protocols)",
"backup_mx": "Relay domain", "backup_mx": "Relay domain",
"bcc": "BCC", "bcc": "BCC",
"bcc_destination": "BCC destination", "bcc_destination": "BCC destination",

View File

@ -198,6 +198,7 @@
<option value="imap"{% if result.attributes.imap_access == '1' %} selected{% endif %}>IMAP</option> <option value="imap"{% if result.attributes.imap_access == '1' %} selected{% endif %}>IMAP</option>
<option value="pop3"{% if result.attributes.pop3_access == '1' %} selected{% endif %}>POP3</option> <option value="pop3"{% if result.attributes.pop3_access == '1' %} selected{% endif %}>POP3</option>
<option value="smtp"{% if result.attributes.smtp_access == '1' %} selected{% endif %}>SMTP</option> <option value="smtp"{% if result.attributes.smtp_access == '1' %} selected{% endif %}>SMTP</option>
<option value="sieve"{% if result.attributes.sieve_access == '1' %} selected{% endif %}>Sieve</option>
</select> </select>
</div> </div>
</div> </div>