先日、メールサーバとして運用していたクラウドサーバを Debian 13 へアップグレードしたのですが、Dovecot のアップグレードが失敗しました。調べたところ、少し根深い問題だったことがわかりましたので、経緯を報告します。
(現状)Postfix + PostfixAdmin + Dovecot + VirutalMail
当方ではマルチドメインのメールを扱うために VirtualMail を使っています。その方法は、例えば、
に書かれていますが、PostfixAdmiin の機能を利用して、メールユーザを仮想ユーザとして管理しています。主な特性を以下にあげます。
- メール受信/送信は Postfix が行う
- ユーザ情報は PostfixAdmin が管理し、MariaDB(MySQL)のデータベースに保存する
- メールに関係する実ユーザは vmail (uid=5000,gid=5000) のみ
- メールボックスは Maildir 形式で /var/vmail/{ドメイン名}/{ユーザ名}に保存される
- ユーザのメールボックスへのアクセスは Dovecot が IMAPS/POP3S で対応する
- ユーザからのメール送信は Dovecot が TLS 経由(465ポート)で受け入れリレーする
Dovecot のアップげレードに失敗する原因
Dovecot が v2.4 にアップデートされたことが主な原因です。さらにつきつめると
- 設定の記述法が変更された
- Dovecot が MD5 で暗号化されたパスワードを受け入れなくなった
これに対して以下で説明する対処を行いました。
(対処1)Dovecot の設定をいったん初期化する
Dovecot のアップグレードが失敗するといっても、新パッケージ自体はインストールできていて、postinst スクリプトが失敗しています。そこで、以下のファイルをパッケージメンテナ版に戻しました。
- /etc/dovecot/dovecont.conf
- /etc/dovecot/conf.d/10-master.conf
- /etc/dovecot/conf.d/10-ssl.conf
これらのファイルはいずれも、カスタマイズしていたものです。これで、一応アップげレードは成功し、dovecot デーモンも起動します。もちろんこの段階ではメールサーバとしては機能しません。
(対処2)Dovecot の設定をカスタマイぜする
現状の設定にあわせるため、次のように設定ファイルを編集しました。いずれのファイルも /etc/dovecot/conf.d/ に配置されています。
service imap-login {
inet_listener imap {
#port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
#port = 110
}
inet_listener pop3s {
port = 995
ssl = yes
}
}
service submission-login {
inet_listener submission {
#port = 587
}
inet_listener submissions {
port = 465
}
}
...
#!include auth-system.conf.ext
!include auth-sql.conf.ext
sql_driver = mysql
mysql localhost {
dbname = postfix
user = postfix
password = xxxxxxxx
}
passdb sql {
default_password_scheme = SHA512
query = \
SELECT username as user, password \
FROM mailbox WHERE username = '%{user}'
}
userdb static {
fields {
uid = vmail
gid = vmail
home = /var/vmail/%{user|domain}/${user|username}
}
}
mail_driver = maildir
mail_path = /var/vmail/%{user|domain}/%{user|username}
mail_uid = 5000
mail_gid = 5000
mail_privileged_group = vmail
ssl = yes
ssl_server_cert_file = /etc/postfix/ssl.crt/mail.example.com.crt
ssl_server_key_file = /etc/postfix/ssl.key/mail.example.com.key
ssl_server_ca_file = /etc/postfix/ssl.crt/example-ca.crt
ssl_min_protocol = TLSv1.2
ssl_server_dh_file = /usr/share/dovecot/dh.pem
(対処3)暗号化方式を変更する
auth-sql.conf.extの中で
passdb sql {
default_password_scheme = SHA512
としていることに注意してください。ここでは暗号化方式として SHA512 を採用しています。Dovecot 2.4 から、MD5 が非推奨になりました。PostfixAdminn は現在、MD5でパスワードを保存していますので、このままでは、Dovecot からの接続ができません。ちなみにデフォルト設定では SHA256 が採用されていますが、SHA512 に変更したのに大きな意味はありません(64bit CPU では、SHA512 の方が少しだけ早いと言われています)。
PostfixAdmin の設定
重要な変更は $CONF['encrypt'] の1箇所だけです(プラス css の問題)。これにより、dovecot の暗号化方式と PostfixAmin の暗号化方式が一致します。
$CONF['encrypt'] = 'dovecot:SHA512-CRYPT';
...
## cssファイルの場所が変わったため、この変更がないと意匠がくずれる
$CONF['theme_css'] = 'static/bootstrap.css';
(対処4)データベースのパスワードを直接に変更する
PostfixAmin の暗号化方式を変更したため、管理ユーザならびに仮想メールユーザがログインできなくなります。これに対処するため、MariaDBのデータベースを直接に変更しました。もっと良い方法があるかもしれませんが、思いつきませんでした。
データベースの中身
データベースでは、管理ユーザのパスワードは admin テーブルに、仮想メールユーザのパスワードは mailbox テーブルにハッシュ化されて保存されています。
$ echo "select username,password from admin" | mariadb -u postfix -pxxxxxxxx postfix
username password
admin@example.com $1$d8809499$AhBV7rqCmGZ1sVOjZNFqs/
$ echo "select username,password from mailbox" | mariadb -u postfix -pxxxxxxxx postfix
username password
user1@example.net $1$d8809499$wcKxWjOnm9R1sXtsO3Jht3
user2@example.net $1$d8809499$ah623bOYPhQ4XqYSshZnr/
user1@example.com $1$d8809499$RNwdKKuzsYSzwTodzyzH8A
user3@example.net $1$d8809499$dV+XWn/gWLTKMWRoO5CqhQ
admin@example.com $1$d8809499$AhBV7rqCmGZ1sVOjZNFqs/
\$1\$ で始まっているのは MD5 でハッシュ化されていることを示しています。\$1\$ の次の8文字はシードで、その次の \$ 以下がハッシュを b64 で表示したものです。もちろん元の生パスワードを推定することは困難です。ただし実際には MD5 のハッシュなら、GPU を駆使して、1時間ほどでハッシュ元(ハッシュなので元パスワードと同じとは限らないが、ログインはできてしまう)を求めることができるようです。
doveamd を使って SHA512 でハッシュ化する
最初に管理者のパスワード(私は管理者なのでそれを知っています)のハッシュを求めます。dovecot には doveadm という便利なコマンドが用意されていて、これを使えばたいていのことができます。
$ doveadm pw -s SHA512-CRYPT
Enter new password:
Retype new password:
{SHA512-CRYPT}$6$dzHRy/Cn6.K1mxe/$BjfQwU9VJFzIBeVPJ6bBuAecTGs40qnJ8O48S2YG5En70Cv1/Oi9e7WFW489PWr2ywrnj8m0JokgzF7LU02dL/
admin / mailbox テーブルに書き込む
このハッシュ値で admin テーブルを変更します。
echo "update admin set password='{SHA512-CRYPT}$6$dz...' where username='admin@example.com' | mariadb -u postfix -pxxxxxxxx postfix
さらに、mailbox テーブルで、管理者自身のパスワードを変更します。
echo "update mailbox set password='{SHA512-CRYPT}$6$dz...' where username='admin@example.com' | mariadb -u postfix -pxxxxxxxx postfix
これにより、管理者ユーザはログインできるようになります。
仮想メールユーザは?
一般の仮想メールユーザについては、管理者はパスワードを知りません。そのため、適当な初期パスワードで同様な操作を行い、mailbox テーブルそ変更します。あとは、ユーザがれぞれに、変更してもらうしかないように思います。
(検証1) doveadm を使用してサーバ上で検証
設定がうまくいったかどうか、doveadm を使って検証できます。
認証の検証
# 認証情報は sudo が必要
$ sudo doveadm auth login admin@example.com xxxxxxxx
passdb: oni@cynetlab.com auth succeeded
extra fields:
user=admin@example.com
userdb user: admin@example.com
userdb extra fields:
uid=5000
gid=5000
home=/var/vmail/example.com/${user|username}
auth_mech=PLAIN
メールボックス内の構成
$ sudo doveadm mailbox list -u admin@example.com
INBOX
# 現在は INBOX フォルダのみ
未読メールのリスト
$ sudo doveadm search -u admin@example.com unseen
30c44903ee85c56801db2a003e6bcc82 1
30c44903ee85c56801db2a003e6bcc82 2
30c44903ee85c56801db2a003e6bcc82 3
...
メールの内容を取得
$ sudo doveadm fetch -u admin@example.com "date.received text.utf8" uid 1
date.received: 2025-03-27 23:58:20
text.utf8:
Return-Path: <admin@example.com>
X-Original-To: admin@example.com
Delivered-To: admin@example.com
Received: by mail.example.com (Postfix, from userid 1000) id E85AFA21CA; Thu, 27 Mar 2025 23:58:20 +0900 (JST)
Date: Thu, 27 Mar 2025 23:58:20 +0900
To: admin@example.com
User-Agent: s-nail v14.9.24
Message-Id: <20250327145820.E85AFA21CA@mail.example.com>
From: debian <admin@mail.example.com>
test
# これはテストメールでした
(検証2) openssl を使用してリモートで検証
リモートからコマンドラインレベルで検証します。imaps/pop3s で開いていますので、telnet ではなく、openssl が必要です。imaps ポートに接続します。
$ openssl s_client -connect mail.example.com:993 -crlf -quiet
Connecting to XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
depth=1 C=JP, ST=Osaka, O=...
verify return:1
depth=0 C=JP, ST=Osaka, O=...
verify return:1
* OK [CAPABILITY IMAP4rev1 LOGIN-REFERRALS ID ENABLE IDLE SASL-IR LITERAL+ AUTH=PLAIN] Dovecot ready.
# IDと平文のパスワードでログインします(セキュア通信なのでOK)。「a01」は適当に選んだプロンプトです
a01 login admin@example.com xxxxxxxx
a01 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE ... NOTIFY LITERAL+] Logged in
# メールボックスの構成を見ます
a01 list "" "*"
* LIST (\HasNoChildren) "." INBOX
a01 OK List completed (0.001 + 0.000 secs).
# INBOX フォルダに入ります
a01 select "INBOX"
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 3961 EXISTS
* 3961 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1757775342] UIDs valid
* OK [UIDNEXT 3962] Predicted next UID
a01 OK [READ-WRITE] Select completed (0.085 + 0.000 + 0.084 secs).
# 含まれる全メールのuidを表示します
a01 search all
* SEARCH 1 2 3 4 5 6 7 8
a01 OK Search completed (0.010 + 0.000 + 0.008 secs).
# ログアウトします
a01 logout
* BYE Logging out
a01 OK Logout completed (0.001 + 0.000 secs).
あとがき
どうやら、Debian 13 へのアップグレードに伴う Dovecot 関連の修正は成功したようです。それにしても、Dovecot のアップグレードに伴う不具合(?)は、Debian としても近来にないものでした(私の感想です)。しかし、メンテナの責任を問うことはできません。仮に私がメンテナであったら、「すみません」と先に誤っておくしかないでしょう。
どちらかというと、Dovecot の責任と言えなくはないですが、結果的にはセキュリティーの向上と、設定ファイルのわかりやすさ(改定後の方が論理的な構成になっています)が得られました。仕方なかったのでしょうか。