バーチャルメールユーザのアカウント情報管理データベースを構築する。OpenLDAP の基本については LDAPのページを参照のこと。
※ LDAP の "ディレクトリ" という語彙はファイルシステムの "ディレクトリ" と区別しにくいため、当ドキュメントでは敢えて「データベース」と呼んでいる。
まず、Qmail-LDAP プロジェクトのホームページから qmail-ldap-1.03-xxxxxxxx.patch.gz をダウンロードする。 それを解凍し、qmail-ldap-1.03-xxxxxxxx.patch ファイルの
diff -upN qmail-1.03/qmail.schema qmail-ldap/qmail.schema --- qmail-1.03/qmail.schema Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail.schema Mon Dec 6 13:55:26 2004 @@ -0,0 +1,279 @@ +# +# qmail-ldap (20030901) ldapv3 directory schema
から、次の
diff -upN qmail-1.03/qmail.sh qmail-ldap/qmail.sh --- qmail-1.03/qmail.sh Thu Jan 1 01:00:00 1970 +++ qmail-ldap/qmail.sh Mon Dec 6 13:55:26 2004
の直前までの行を別ファイルに保存する。/home/hoshu/cabinet/qmail.schema.patch ファイルとして保存したとしよう。そうしたら、空のディレクトリでパッチを適用することによって qmail.schema ファイルを生成する;
hoshu$ cd ~/cabinet hoshu$ mkdir qmail-ldap hoshu$ cd qmail-ldap hoshu$ patch -p1 <../qmail.schema.patch
できた qmail.schema ファイルを root 権限で /etc/openldap/schema/ にコピーする。
使用するクラス/スキーマをまとめると下表のようになる。■地は直接使用するクラス、■のものは直接使用クラスが継承しているため暗黙的に使用されるクラス。
Class | 父Class | 祖父Class | 曾祖父Class | 直接使用Classのタイプ | Class提供スキーマ |
Top | - | core.schema | |||
uidObject | AUXILIARY | ||||
inetOrgPerson | organizationalPerson | person | STRUCTURAL | inetorgperson.schema (cosine.schema) |
|
posixAccount | AUXILIARY | nis.schema | |||
qmailUser | AUXILIARY | qmail.schema |
※ cosine.schema は、inetorgperson.schema の中の一部のクラスがそれに依存しているためロードする必要がある。
オリジナルの /etc/openldap/slapd.conf を、必要ならバックアップしてから、下記の内容に置き換える。
include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/qmail.schema allow bind_v2 <--これがないとPostfixでは動作が成り立たなかった pidfile /var/run/openldap/slapd.pid <--※1 argsfile /var/run/openldap/slapd.args access to dn.subtree="ou=mail,o=hoge,dc=cxm" <--LDAPアカウント mailadmin しか読めないよう規制 by dn="cn=mailadmin,ou=mail,o=hoge,dc=cxm" read by anonymous auth by * none database bdb suffix "o=hoge,dc=cxm" rootdn "cn=Manager,o=hoge,dc=cxm" rootpw {SMD5}UFq1pseeDIL3bt6CzTMw6uJUdyg= <--※2 directory /var/lib/ldap index objectClass eq,pres index ou,cn,mail,surname,givenname eq,pres,sub index uidNumber,gidNumber,loginShell eq,pres index uid,memberUid eq,pres,sub index nisMapName,nisMapEntry eq,pres,sub password-hash {CLEARTEXT} <--※3
準備が整ったら LDAP サーバデーモン slapd を開始し、エラーが出なければスタートアップに登録;
root# service ldap start root# chkconfig ldap on
これから構築するのは左図のようなLDAP Directory ツリー。"o=hoge,dc=cxm" 直属の "cn=Manager"(rootdn) や、"ou=mail,o=hoge,dc=cxm"サブツリーの "cn=mailadmin" は LDAP管理/運営用の特別なユーザ、"cn=stray" や "cn=penguin" などが実際のバーチャルメールドメインユーザだ。
まずこの項では、入れ物となるツリーを作成し、管理用ユーザの登録までを行う。
サンプルとして、LDIF ファイル framework.hoge.cxm.ldif を用意しておいたので、適宜編集し、ldapadd で投入する;
hoshu$ ldapadd -x -D "cn=Manager,o=hoge,dc=cxm" \ -w PASSWORD \ -f framework.hoge.cxm.ldif
投入できたか確認してみる;
hoshu$ ldapsearch -x -LLL -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ -b "o=hoge,dc=cxm"
次にユーザデータ読み取り専用の管理ユーザ mailadmin を登録する。サンプルファイルは mailadmin.ldif。userPassword 属性値は、後述の「事前MD5方式」や「LDAP=CRYPT方式」に関係なく LDAP-SMD5 形式で書いておく (サンプルファイルのパスワードは `password')。では登録しよう;
hoshu$ ldapadd -x -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ -f mailadmin.ldif
好みのパスワードに変更するには、運用上の password-hash 設定に影響されずに希望の形式で格納させるため、敢えて、パスワード変更拡張手順の使用されない ldapmodify コマンドで行う;
hoshu$ /usr/sbin/slappasswd -h '{SMD5}' -s Password {SMD5}xxxxxxxxxxxxxxxxx= hoshu$ ldapmodify -x -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD dn: cn=mailadmin,ou=mail,o=hoge,dc=cxm userPassword: {SMD5}xxxxxxxxxxxxxxxxx= <--上記 slappasswd で出力されたものを貼り付ける <Enter> <Ctrl + d>
qmail.schema によって実装される qmailUser クラスの力を借りて下表のような属性を備えたエントリを作成する。qmailUser クラスの属性の説明は Qmail-LDAP プロジェクトホームページの Category:LDAP Fields にある。属性の味付けや使い方は Postfix と Dovecot の LDAP参照定義でどうにでもなるのだが、なるべく qmailUser の規格に逆らわない使い方をしている。
[凡例] | |
必須 列: | ◎=属性規格上も運用上も必須, □=属性の規格上必須, ○=運用上必須, △=省略可能 |
型 列: | IA5=文字列型, int=数値, OctStr=オクテット文字列, DirStr=LDAPディレクトリ文字列 |
Case 列: | 検索時に大文字小文字の区別がされるか。「無視」の場合でもデータ登録時に大文字が登録できないわけではない |
比較 列: | 検索時のマッチ条件。完全=長さも等しくなければ一致しない, 数値=数値として比較, OctStr=オクテット文字列比較 |
多重 列: | 同じ属性を別の値で複数回登録できるか |
Attribute | 説明 | 属性パターン | 属性提供元 最上流クラス |
||||
必須 | 型 | Case | 比較 | 多重 | |||
cn | メールアドレスの @domain.tld より前の部分。 | ◎ | DirStr | 無視 | 完全 | 不可 | person |
sn | 本来の意味は苗字だが、実際には何にも活用されない。便宜上 organization (つまり "hoge") を入力しておく。複数のバーチャルメール(サブ)ドメインを運用する場合にはサブドメイン名 (例えば "sales") を入れておくという使い方もいいかもしれない。 | ◎ | DirStr | 無視 | 完全 | 不可 | person |
uid | cn と同じものを入力する。 | ◎ | DirStr | 無視 | 完全 | 不可 | uidObject |
正メールアドレス。ドメイン部も含めて stray@hoge.cxm のように登録する。 | ◎ | IA5 | 無視 | 完全 | 不可 | inetOrgPerson | |
uidNumber | Dovecot が内部的に使用する。全員共通でシステムユーザ mailadmin の UID を登録しておいてもいいが、できれば一意となるように 500, 501, 502... といった値を登録しておくのが確実。 | □ | int | - | 数値 | 不可 | posixAccount |
gidNumber | 上記同様。こちらは全員必ず mailadmin の GID を登録しておく。 | □ | int | - | 数値 | 不可 | posixAccount |
userPassword | Dovecot の POP3 認証用パスワード。Dovecot 0.99 で使うには、登録時に平文で渡して LDAP 側で CRYPT させるか、あらかじめ MD5 ハッシュしておいたものをそのまま格納させるかのどちらか。(※補足1) | ○ | OctStr | 厳格 | OctStr | 不可 | person |
homeDirectory | メールボックスの所在。Postfix (virtual_mailbox_maps 機能を経由) でも Dovecot (auth_userdb) でも使用される。/users/USERNAME の形で登録 (例えば /users/penguin)。当該ユーザのメールボックスパスは、Postfix, Dovecot の然るべき設定によって、最終的に /var/vmail<homeDirectory>/Maildir/ と解釈される。(※補足2) | ○ | IA5 | 厳格 | 完全 | 不可 | posixAccount |
mailForwardingAddress | Forward または BCC 先メールアドレス。この属性の値を Forward 先として扱うか BCC 先として扱うかは下記の deliveryMode で決まる。Forward の場合に限っては、この属性を別の値で複数回登録しておくことも可能で、そうすると、受信メールを複数のメールアドレスへ転送することができる。BCC の場合の複数登録は Postfix がサポートしておらず、メールヘッダが異常なものになり送信不能となる。注意して使えば多重転送も可能だが、Postfix のループ防止機構により以下の制限がある; ●Forward先ユーザで更に Forward : 可能 ●BCC先ユーザで更に Forward : 可能 ●Forward先ユーザで更に BCC : 不可能 ●BCC先ユーザで更に BCC : 不可能 |
△ | IA5 | 無視 | 完全 | 可 | qmailUser |
deliveryMode | mailForwardingAddress が Forward 先か BCC 先かを決定する。値は 3種類; ●noforward : 通常の配送。mailForwardingAddress が登録してあったとしても、Forward も BCC もしない。 ●nolocal : Forward 動作。正メールボックスには配送せず mailForwardingAddress にだけ配送する。 ●この属性が存在しない時 : BCC 動作。正メールボックスとともに mailForwardingAddress にも配送する。 |
△ | IA5 | 無視 | 完全 | 不可 | qmailUser |
accountStatus | このアカウントが有効か無効か。ユーザエントリを LDAP データベースから削除しなくても、そのユーザをいないことにできる。値は 2種類; ●disabled : 無効。LDAP検索にヒットしない。直接メールを受け取らないアカウントだとしても Forward/BCC 元として参照される必要がある場合には無効にしてはならない。 ●active またはこの属性が存在しない時 : 有効。通常通り LDAP検索にヒットする。 |
△ | IA5 | 無視 | 完全 | 不可 | qmailUser |
いよいよ実際にバーチャルメールドメインユーザを登録する。ただし、Postfix と Dovecot の設定が完了するまでは、2~3 のテストユーザを登録するに留めておくのがいいだろう。使っているバージョンの Dovecot がやりたいことに対応していなかったりして途中で実装方針が変わり、大量のエントリを全部登録しなおすハメになるのは悲しいではないか。
LDIF ファイル上の 1エントリは下のような記述になる。サンプルファイル (users.mail.hoge.cxm.ldif) を置いておくので、雛形にするといいだろう。
dn: cn=penguin,ou=mail,o=hoge,dc=cxm objectClass: uidObject objectClass: inetOrgPerson objectClass: posixAccount objectClass: qmailUser uid: penguin cn: penguin sn: hoge mail: penguin@hoge.cxm uidNumber: 502 gidNumber: 1025 userPassword: 5f4dcc3b5aa765d61d8327deb882cf99 homeDirectory: /users/penguin deliveryMode: noforward accountStatus: active
上記のサンプルファイルの userPassword 属性の値は、事前MD5方式 を前提としている。5f4dcc... は "password" というパスワードを mkmd5.pl スクリプトで MD5 ハッシュしたものだ。好きなパスワードのハッシュに入れ替えたければ、
hoshu$ mkmd5.pl sukina-password
として吐き出されたものを貼り付ける。そして登録;
hoshu$ ldapadd -x -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ -f users.mail.hoge.cxm.ldif
LDAP-CRYPT方式 の場合、投入時の userPassword はダミーにしかならないので、とにかく何か書いてあればいい。まず登録;
hoshu$ ldapadd -x -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ -f users.mail.hoge.cxm.ldif
そして、本当のパスワードに書き換える。上記サンプルで示した penguin アカウントの例;
hoshu$ ldappasswd -x -S -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ "cn=penguin,ou=mail,o=hoge,dc=cxm" New passsword: password Re-enter new password: password
意図した形式で格納されたかどうか確認したい場合は、例えば以下のようにすればよい。userPassword 属性は Base64 でエンコードして格納されていることをお忘れなく。これまた penguin アカウントを例に採る。
hoshu$ ldapsearch -x -LLL -D "cn=mailadmin,ou=mail,o=hoge,dc=cxm" -w PASSWORD \ -b "ou=mail,o=hoge,dc=cxm" -s one \ '(&(objectClass=inetOrgPerson)(cn=penguin))' userPassword dn: cn=penguin,ou=mail,o=hoge,dc=cxm userPassword: xxxxxxxxxxxxxxxx=
下記コマンドの xxxx の部分に上記応答の xxxxxxxxxxxxxxxx= を貼り付けて、
hoshu$ perl -MMIME::Base64 -e 'print decode_base64("xxxx"), "\n";'
とすれば、「事前MD5方式」の場合は LDIF に書いたままの文字列、「LDAP-CRYPT方式」なら '{CRYPT}yyyyyyyy ' といった文字列が得られるはずだ。
Postfix は、バーチャルメールユーザへの初めてのメールを配送する時に配送先ディレクトリが存在しないと、親ディレクトリも含めて自動的に作成しようとする。しかし、勝手に作られるのは気持ち悪い。また、1通も受信しないうちにそのユーザが POP3 アクセスして来るかもしれない。Dovecot は勝手にディレクトリを作ったりしないので、ユーザのメールクライアントへエラーが返る結果となってしまう。そこで、ユーザメールボックスは、LDAP データベースにユーザエントリを登録し次第、管理者側で用意してやることにする。下記に示す階層構造 (penguin/ 以下) を適切なパーミッションで作成しなければならない。
/var/vmail/users/ \_ penguin/ [mailadmin:mailadmin 700] \_ Maildir/ [mailadmin:mailadmin 700] \_ new/ [mailadmin:mailadmin 700] cur/ [mailadmin:mailadmin 700] tmp/ [mailadmin:mailadmin 700]
いちいち手作業でこれをやるのは面倒臭いしミスも起こりやすいので、シェルスクリプトにした - vmaildirmake
root# vmaildirmake USER
という具合に使う。引数なしで呼ぶと簡単なヘルプが表示される。基底ディレクトリが /var/vmail/users/ 以外の時や読み書き専用 UNIXアカウントの名前が mailadmin でない場合はスクリプトファイル冒頭の変数を適宜調整していただきたい。
何かの条件下で、バーチャルメールドメインの root や postmaster つまり、root@hoge.cxm や postmaster@hoge.cxm へメールが届くケースがないともいえない。特に、メールトラブルなどの連絡先として postmaster を公表している場合だ。しかし、このメールサーバで複数のメールサブドメインを運営する場合、それぞれのバーチャルドメインの postmaster へメールが行くのは運用上煩雑だ。そこで、後述の Postfix 設定で、virtual_alias_maps 機能を利用して全てのバーチャルメールドメイン配下の特別なアカウントを実アカウントへ一旦エイリアスし、さらにマシンローカルの aliases ファイルで最終的なユーザなりメールアドレスなりへとエイリアスする。
そこで肝となるのが、そもそも Postfix は、アカウントデータベースに存在しないユーザへのメールは SMTPセッション段階で拒絶し、virtual_aliases を参照するまでに至らないという点だ。そのため、とにかく存在する ということを示すためだけに、それら特別なアカウントもダミー的に LDAP のユーザ階層に登録しておく必要がある。
ほとんどの場合、サンプルファイル aliasusers.mail.hoge.cxm.ldif に挙げたアカウント群で間に合うだろう。そのひとつ、postmaster の LDIF エントリを覗いてみるとしよう;
dn: cn=postmaster,ou=mail,o=hoge,dc=cxm objectClass: uidObject objectClass: inetOrgPerson objectClass: posixAccount objectClass: qmailUser uid: postmaster cn: postmaster sn: hoge mail: postmaster@hoge.cxm uidNumber: 1025 <--使われないが、mailadmin の UID を登録 gidNumber: 1025 <--使われないが、mailadmin の GID を登録 userPassword: ffffffffffffffffffffffffffffffff <--パスワードはダミーで構わない homeDirectory: /users/postmaster <--使われないが、他のバーチャルユーザと同様にしておく deliveryMode: noforward <--転送しない noforward にしておく accountStatus: active <--必ず active に
LDAP に登録する;
hoshu$ ldapadd -x -D "cn=Manager,o=hoge,dc=cxm" -w PASSWORD \ -f aliasusers.mail.hoge.cxm.ldif