From 81a6f8808be13b3f844cddf6504343e02d0dea81 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 21 Dec 2023 19:03:31 +0000 Subject: [PATCH] fix: escape login and password when passed from dovecot to doveauth This should allow to use / in the password --- chatmaild/src/chatmaild/doveauth.py | 30 ++++++++++++++++++- .../src/chatmaild/tests/test_doveauth.py | 3 +- cmdeploy/src/cmdeploy/dovecot/auth.conf | 9 ++++-- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/chatmaild/src/chatmaild/doveauth.py b/chatmaild/src/chatmaild/doveauth.py index 68418dbe..a5e978ae 100644 --- a/chatmaild/src/chatmaild/doveauth.py +++ b/chatmaild/src/chatmaild/doveauth.py @@ -98,6 +98,32 @@ def lookup_passdb(db, config: Config, user, cleartext_password): ) +def split_and_unescape(s): + """Split strings using double quote as a separator and backslash as escape character + into parts.""" + + out = "" + i = 0 + while i < len(s): + c = s[i] + if c == "\\": + # Skip escape character. + i += 1 + + # This will raise IndexError if there is no character + # after escape character. This is expected + # as this is an invalid input. + out += s[i] + elif c == '"': + # Separator + yield out + out = "" + else: + out += c + i += 1 + yield out + + def handle_dovecot_request(msg, db, config: Config): short_command = msg[0] if short_command == "L": # LOOKUP @@ -107,7 +133,9 @@ def handle_dovecot_request(msg, db, config: Config): # do not attempt to read any other parts for compatibility. keyname = parts[0] - namespace, type, *args = keyname.split("/") + namespace, type, args = keyname.split("/", 2) + args = list(split_and_unescape(args)) + reply_command = "F" res = "" if namespace == "shared": diff --git a/chatmaild/src/chatmaild/tests/test_doveauth.py b/chatmaild/src/chatmaild/tests/test_doveauth.py index 927e03c8..8c967b94 100644 --- a/chatmaild/src/chatmaild/tests/test_doveauth.py +++ b/chatmaild/src/chatmaild/tests/test_doveauth.py @@ -52,8 +52,9 @@ def test_too_high_db_version(db): def test_handle_dovecot_request(db, example_config): + # Test that password can contain ", ', \ and / msg = ( - "Lshared/passdb/laksjdlaksjdlaksjdlk12j3l1k2j3123/" + 'Lshared/passdb/laksjdlaksjdlak\\\\sjdlk\\"12j\\\'3l1/k2j3123"' "some42123@chat.example.org\tsome42123@chat.example.org" ) res = handle_dovecot_request(msg, db, example_config) diff --git a/cmdeploy/src/cmdeploy/dovecot/auth.conf b/cmdeploy/src/cmdeploy/dovecot/auth.conf index 0664f70b..304404af 100644 --- a/cmdeploy/src/cmdeploy/dovecot/auth.conf +++ b/cmdeploy/src/cmdeploy/dovecot/auth.conf @@ -1,5 +1,10 @@ uri = proxy:/run/dovecot/doveauth.socket:auth iterate_disable = yes default_pass_scheme = plain -password_key = passdb/%w/%u -user_key = userdb/%u +# %E escapes characters " (double quote), ' (single quote) and \ (backslash) with \ (backslash). +# See +# for documentation. +# +# We escape user-provided input and use double quote as a separator. +password_key = passdb/%Ew"%Eu +user_key = userdb/%Eu