From afb43c9c5b4ac2cd6d9cc2c499b2c24e6f913cef Mon Sep 17 00:00:00 2001 From: andryyy Date: Tue, 3 Dec 2019 18:50:45 +0100 Subject: [PATCH] [Dovecot] Fix app passwds: allow multiple pass hashes by using LUA construct --- data/Dockerfiles/dovecot/Dockerfile | 1 + data/Dockerfiles/dovecot/docker-entrypoint.sh | 56 ++++++++++++------- data/conf/dovecot/dovecot.conf | 4 +- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/data/Dockerfiles/dovecot/Dockerfile b/data/Dockerfiles/dovecot/Dockerfile index e52f65d8..5279d0f3 100644 --- a/data/Dockerfiles/dovecot/Dockerfile +++ b/data/Dockerfiles/dovecot/Dockerfile @@ -69,6 +69,7 @@ RUN groupadd -g 5000 vmail \ libunicode-string-perl \ liburi-perl \ libwww-perl \ + lua-sql-mysql \ mariadb-client \ procps \ python3-pip \ diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index 097895ab..3bba169d 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -7,21 +7,6 @@ while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${D sleep 2 done -# Hard-code env vars to scripts due to cron not passing them to the scripts -sed -i "s/__DBUSER__/${DBUSER}/g" /usr/local/bin/imapsync_cron.pl -sed -i "s/__DBPASS__/${DBPASS}/g" /usr/local/bin/imapsync_cron.pl -sed -i "s/__DBNAME__/${DBNAME}/g" /usr/local/bin/imapsync_cron.pl - -sed -i "s/__DBUSER__/${DBUSER}/g" /usr/local/bin/quarantine_notify.py -sed -i "s/__DBPASS__/${DBPASS}/g" /usr/local/bin/quarantine_notify.py -sed -i "s/__DBNAME__/${DBNAME}/g" /usr/local/bin/quarantine_notify.py - -sed -i "s/__DBUSER__/${DBUSER}/g" /usr/local/bin/clean_q_aged.sh -sed -i "s/__DBPASS__/${DBPASS}/g" /usr/local/bin/clean_q_aged.sh -sed -i "s/__DBNAME__/${DBNAME}/g" /usr/local/bin/clean_q_aged.sh - -sed -i "s/__LOG_LINES__/${LOG_LINES}/g" /usr/local/bin/trim_logs.sh - # Create missing directories [[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/ [[ ! -d /var/vmail/_garbage ]] && mkdir -p /var/vmail/_garbage @@ -127,12 +112,35 @@ default_pass_scheme = SSHA256 password_query = SELECT password FROM mailbox WHERE active = '1' AND username = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') AND JSON_EXTRACT(attributes, '$.force_pw_update') NOT LIKE '%%1%%' EOF -cat < /etc/dovecot/sql/dovecot-dict-sql-app-passdb.conf -# Autogenerated by mailcow -driver = mysql -connect = "host=/var/run/mysqld/mysqld.sock dbname=${DBNAME} user=${DBUSER} password=${DBPASS}" -default_pass_scheme = SSHA256 -password_query = SELECT password FROM app_passwd WHERE active = '1' AND mailbox = '%u' AND domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') +cat < /var/lib/dovecot/app-passdb.lua +function auth_password_verify(req, pass) + local cur,errorString = con:execute(string.format([[SELECT mailbox, password FROM app_passwd + WHERE mailbox = '%s' + AND active = '1' + AND domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], 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 + req.log_warning(req, string.format("User %s logged in with app password", row.mailbox)) + cur:close() + return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass + end + row = cur:fetch (row, "a") + end + return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "no such user" +end + +function script_init() + mysql = require "luasql.mysql" + env = mysql.mysql() + con = env:connect("__DBNAME__","__DBUSER__","__DBPASS__","mysql") + return 0 +end + +function script_deinit() + con:close() + env:close() +end EOF # Migrate old sieve_after file @@ -206,6 +214,12 @@ else rm -f /etc/dovecot/sogo-sso.conf fi +# Hard-code env vars to scripts due to cron not passing them to the scripts +sed -i "s/__DBUSER__/${DBUSER}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /var/lib/dovecot/app-passdb.lua +sed -i "s/__DBPASS__/${DBPASS}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /var/lib/dovecot/app-passdb.lua +sed -i "s/__DBNAME__/${DBNAME}/g" /usr/local/bin/imapsync_cron.pl /usr/local/bin/quarantine_notify.py /usr/local/bin/clean_q_aged.sh /var/lib/dovecot/app-passdb.lua +sed -i "s/__LOG_LINES__/${LOG_LINES}/g" /usr/local/bin/trim_logs.sh + # 401 is user dovecot if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index 01243091..27fa834b 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -56,8 +56,8 @@ passdb { } # try an app passwd passdb { - args = /etc/dovecot/sql/dovecot-dict-sql-app-passdb.conf - driver = sql + driver = lua + args = file=/var/lib/dovecot/app-passdb.lua blocking=yes pass = yes result_failure = continue result_internalfail = continue