From 644b1f85d1b5ff43425c503c56554ac1c8d1d0a9 Mon Sep 17 00:00:00 2001 From: andryyy Date: Sat, 30 Oct 2021 08:03:41 +0200 Subject: [PATCH] [Dovecot, Web] Allow SOGo access with app password when imap is disabled; Add sieve to mailbox protocol access restrictions --- data/Dockerfiles/dovecot/docker-entrypoint.sh | 24 ++++++++++++------- data/web/inc/footer.inc.php | 4 +++- data/web/inc/functions.mailbox.inc.php | 6 +++++ data/web/lang/lang.de.json | 2 +- data/web/lang/lang.en.json | 2 +- data/web/templates/edit/mailbox.twig | 1 + 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 6645331b..2ae2c407 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -155,9 +155,10 @@ function auth_password_verify(req, pass) local row = cur:fetch ({}, "a") while row do 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) 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 end row = cur:fetch (row, "a") @@ -166,25 +167,31 @@ function auth_password_verify(req, pass) -- check against app passwds for imap and smtp -- 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 - 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 WHERE mailbox = '%s' - AND app_passwd.%s_access = '1' AND app_passwd.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") while row do 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) - VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip))) - return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass + -- 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) + 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 + end end row = cur:fetch (row, "a") end end + cur:close() + con:close() + return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate" -- PoC @@ -232,6 +239,7 @@ EOF 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/__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 diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php index 9a438666..4a66d466 100644 --- a/data/web/inc/footer.inc.php +++ b/data/web/inc/footer.inc.php @@ -42,7 +42,9 @@ foreach ($globalVariables as $globalVariableName => $globalVariableValue) { $twig->addGlobal($globalVariableName, $globalVariableValue); } -echo $twig->render($template, $template_data); +if (is_array($template_data)) { + echo $twig->render($template, $template_data); +} if (isset($_SESSION['mailcow_cc_api'])) { session_regenerate_id(true); diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 7f0aea89..21b6b130 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -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']); $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']); $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']); @@ -975,6 +976,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'imap_access' => strval($imap_access), 'pop3_access' => strval($pop3_access), 'smtp_access' => strval($smtp_access), + 'sieve_access' => strval($sieve_access), 'relayhost' => strval($relayhost), 'passwd_update' => time(), '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['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; } if (!empty($is_now)) { $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)$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)$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)$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']; @@ -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`, '$.sogo_access', :sogo_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`, '$.relayhost', :relayhost), `attributes` = JSON_SET(`attributes`, '$.smtp_access', :smtp_access) @@ -2626,6 +2631,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ':sogo_access' => $sogo_access, ':imap_access' => $imap_access, ':pop3_access' => $pop3_access, + ':sieve_access' => $sieve_access, ':smtp_access' => $smtp_access, ':relayhost' => $relayhost, ':username' => $username diff --git a/data/web/lang/lang.de.json b/data/web/lang/lang.de.json index 33fadb41..e5e067dc 100644 --- a/data/web/lang/lang.de.json +++ b/data/web/lang/lang.de.json @@ -506,7 +506,7 @@ "alias": "Alias bearbeiten", "allow_from_smtp": "Nur folgende IPs für SMTP erlauben", "allow_from_smtp_info": "Leer lassen, um keine Prüfung durchzuführen.
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_passwd": "App-Passwörter", "app_passwd_protocols": "Zugelassene Protokolle für App-Passwort", diff --git a/data/web/lang/lang.en.json b/data/web/lang/lang.en.json index d060b6ec..052662dc 100644 --- a/data/web/lang/lang.en.json +++ b/data/web/lang/lang.en.json @@ -705,7 +705,7 @@ "all_domains": "All Domains", "allow_from_smtp": "Only allow these IPs to use SMTP", "allow_from_smtp_info": "Leave empty to allow all senders.
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", "bcc": "BCC", "bcc_destination": "BCC destination", diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig index 8ff48332..ecfc75cc 100644 --- a/data/web/templates/edit/mailbox.twig +++ b/data/web/templates/edit/mailbox.twig @@ -198,6 +198,7 @@ +