Browse Source

[Dovecot] Fix app passwds: allow multiple pass hashes by using LUA construct

andryyy 5 years ago
parent
commit
afb43c9c5b

+ 1 - 0
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 \

+ 35 - 21
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 <<EOF > /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 <<EOF > /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

+ 2 - 2
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