利用例3 メールに活用

最近のMTA(Mail Transfer Agent)はLDAPを参照して、宛先を決定することができるようになっています。またIMAPサーバなどでもLDAPを参照してメールボックスを決定することができるようにもなっています。これらの設定の仕方について簡単に説明します。

LDAPを使ってメールのフォワードをする

Debian 2.2(potato)では、標準のMTAであるeximが既にLDAPをサポートしています。なお開発版のsidではpostfixなどもLDAPサポートが追加されています。ここではpotatoにあるeximでLDAPを使う場合について簡単に説明します。なお、eximを普通に動かす方法についてはここでは説明しません。ここの例ではeximはexample.jpドメインのメールを処理するものとします。

exim側の設定

eximでLDAPを参照する一番簡単な方法はaliasfileでLDAPを見るように設定することです。

exim.confにリスト1のような設定をsystem_aliases:の定義の後ろに追加します。これによりaliasfileドライバを使うldap_aliases:が定義されます。普通のaliasでは検索タイプ(search_type)はlsearchなどを使いますが、ここではldapもしくはldapmを使います。ldapmを使うと複数のエントリからの結果も使うことができるという点がldapと違います。この設定で$local_part@example.jp宛のメールはlocalhostのポート389のLDAPサーバでuid=$local_part,ou=People,dc=example,dc=jpを検索して、そのmailアトリビュートをaliasを展開したものとして使うようになります(図1)

リスト1 exim.confのLDAPについての設定
ldap_aliases:
  driver = aliasfile
  search_type = ldapm
  query = "ldap://localhost:389/uid=$local_part,ou=People,dc=example,dc=jp?mail?base?"
図1 aliasの展開
| 
| $local_part@example.jp
|         |
| -----  exim -----
|         |
|         v
|    ldap_aliases:
|          ---- query --------------------------------------------->  
|             basedn = uid=$local_part,ou=People,dc=example,dc=jp
|             scope = base                                           LDAP server
|             attribute = mail 
|          <--------------------------------------------------------
|          |
|          v
|     uid=$local_part,ou=People,dc=example,dc=jpの
|      mailアトリビュートの値
| 

queryに指定するのはRFC2255「The LDAP URL Format」に従った記述方法でLDAPの検索方法を指定します。

ldap://localhost:389/uid=$local_part,ou=People,dc=example,dc=jp?mail?base?

この例では次のような意味になります。

つまり上のURLは以下のようなコマンドの実行結果と同等の意味になります。

% ldapsearch -x -h localhost -p 389 -s base -b "uid=$local_part,ou=People,dc=example,dc=jp" '(objectclass=*)' mail

ここで-s baseというのが検索範囲を指定するためのオプションです。

次のような書きかたもできます。

ldap:///dc=example,dc=jp?mail?sub?uid=$local_part

この場合は以下のような意味になります。

なお、この場合ldap_default_serversに次のように指定しておくとLDAPサーバとしてldap1.example.jpのポート10389とldap2.example.jpのポート389(ldapのデフォルトポート)を使うようになります。ldap_default_serversはコロンで区切るのでポートを指定する時はコロンを二つ::使わなければなりません。

ldap_default_servers = ldap1.example.jp::10389:ldap2.example.jp

このURLをldapsearchで同じように検索するとすると次のようになります。

% ldapsearch -x -b "dc=example,dc=jp" "uid=$local_part" mail

LDAP側に登録

eximが期待するような情報をLDAPに登録する必要があります。リスト1のような設定にする場合uid=$local_part,ou=People,dc=example,dc=jpがmailという属性をもてばいいことになります。

mailという属性はcore.schemaにリスト2のように定義されているのでこれを使うことができます。このmailを含むようなobjectclassの定義はinetorgperson.schemaにリスト3のように定義されているのでこれを使うことにします。

リスト2 mail属性の定義
attributetype ( 0.9.2342.19200300.100.1.3
       NAME ( 'mail' 'rfc822Mailbox' )
       DESC 'RFC1274: RFC822 Mailbox'
   EQUALITY caseIgnoreIA5Match
   SUBSTR caseIgnoreIA5SubstringsMatch
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
リスト3 objectclass inetOrgPersonの定義
objectclass     ( 2.16.840.1.113730.3.2.2
    NAME 'inetOrgPerson'
       DESC 'RFC2798: Internet Organizational Person'
   SUP organizationalPerson
   STRUCTURAL
       MAY (
               audio $ businessCategory $ carLicense $ departmentNumber $
               displayName $ employeeNumber $ employeeType $ givenName $
               homePhone $ homePostalAddress $ initials $ jpegPhoto $
               labeledURI $ mail $ manager $ mobile $ o $ pager $
               photo $ roomNumber $ secretary $ uid $ userCertificate $
               x500uniqueIdentifier $ preferredLanguage $
               userSMIMECertificate $ userPKCS12 )
       ) 

例えばfoo@example.jpのメールをfoo@example.netに転送する場合、uid=foo,ou=People,dc=example,dc=jpはリスト4のようなLDIFにしておけばいいことになります。このようにobjectclassとしてinetOrgPersonを追加して、mail: foo@example.netを追加します。さらに、objectclass inetOrgPersonはsn属性(surname; 姓)も必要とするのでsn: fooを追加してあります。このように追加するためのldapmodifyに入力するためのLDIFはfoo-mail.ldif(リスト5)のようになります。

リスト4 foo@example.jpのmailを含むLDIFの例
dn: uid=foo,ou=people,dc=example,dc=jp
uid: foo
objectClass: posixAccount
objectClass: shadowAccount
objectClass: inetOrgPerson
homeDirectory: /home/foo
cn: foo bar
sn: foo
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
uidNumber: 1001
gidNumber: 1001
loginShell: /usr/bin/zsh
gecos: foo,0000,1111,2222
shadowLastChange: 11588
mail: foo@example.net
リスト5 mailを追加するLDIF, foo-mail.ldif
dn: uid=foo,ou=People,dc=example,dc=jp
changetype: modify
add: objectclass
objectclass: inetOrgPerson
-
add: sn
sn: foo
-
add: mail
mail: foo@example.net

まずinetOrgPersonを使うのでinetorgperson.schemaをincludeするようslapd.confにリスト6の行を追加する必要があります。

リスト6 inetorgperson.schemaのinclude
include /usr/local/etc/openldap/schema/inetorgperson.schema

追加したらslapdを起動しなおします。

# kill `cat /usr/local/var/slapd.pid`
# /usr/local/libexec/slapd

それからldapmodifyでディレクトリエントリの修正をします。

% ldapmodify -D 'cn=Manager,dc=example,dc=jp' -W -f foo-mail.ldif
Enter LDAP password: 
modifying entry "uid=foo,ou=People,dc=example,dc=jp"

これでfoo@example.jp宛のメールが届くと、exim.confで設定したldap_alias:のqueryで指定してLDAP URLを使ってmailを検索して得られた値、つまりuid=foo,ou=People,dc=example,dc=jpのmailアトリビュートの値 foo@example.netにメールを送るようになります。 一つのディレクトリエントリに複数のmailがあればそれが展開されてそれぞれの宛先に送られるようになります。従って例えばリスト7のようなディレクトリエントリの場合foo@example.jpはfoo@example.netとfoo@example.orgの二箇所に送られるようになります。これを応用すればグループに対するメールや簡単なメイリングリストのメンバー管理もLDAPで行なえるようになります。この場合はobjectclass: nisMailAliasで、rfc822MailMemberというアトリビュートを使うほうがいいのかもしれません。これらはmisc.schemaに定義されているのでこれをincludeして使うことになります(リスト8)。

リスト7 複数のmailを含むLDIFの例
dn: uid=foo,ou=people,dc=example,dc=jp
uid: foo
objectClass: posixAccount
objectClass: shadowAccount
objectClass: inetOrgPerson
homeDirectory: /home/foo
cn: foo bar
sn: foo
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
uidNumber: 1001
gidNumber: 1001
loginShell: /usr/bin/zsh
gecos: foo,0000,1111,2222
shadowLastChange: 11588
mail: foo@example.net
mail: foo@example.org
リスト8 misc.schemaのinclude
include /usr/local/etc/openldap/schema/misc.schema

LDAPを使ってメールアカウントを管理する

eximとcourier-imapを使うとLDAPでメールアカウントの管理をすることができます。

OpenLDAP-2.0.18ではmisc.schemaにmailLocalAddressなどがあるのでこれを使うことにします(リスト9)。残念ながらこのアトリビュートをもつinetLocalMailRecipientにはまだOID(Object Identifier)がわりあててられていないので、そのままでは使うことができません。現状ではschemacheck offにすることでobjectclassによる持つことのでくる属性のチェックをはずす必要があります(リスト10)。

リスト9 mailLocalAddress属性
attributetype ( 2.16.840.1.113730.3.1.13
       NAME 'mailLocalAddress'
       DESC 'RFC822 email address of this recipient'
       EQUALITY caseIgnoreIA5Match
       SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
リスト10 misc.schemaのincludeとschemacheck off
include /usr/local/etc/openldap/schema/misc.schema
schemacheck off

まず、LDAPでどのように情報を持つかを決める必要があります。ここでは図2のようにすることにします。mailLocalAddress属性が受信するe-mailアドレスです。このアドレスにきたメールはmail属性で示されるディレクトリにMaildir形式でスプールします。userPasswordアトリビュートはこのスプールに対するIMAPでアクセスする時のパスワードです。なお、courier-imapはLDAPを参照する時にもホームディレクトリを必要とするのでhomeDirectoryアトリビュートに指定しておきます。メールは配送とLDAPの関係は図3のようになります。

図2 メールに関するエントリのもちかたの例
dn: uid=bar,ou=people,dc=example,dc=jp
uid: bar
objectClass: top
cn: foo bar
mailLocalAddress: bar@example.jp
mail: /var/local/maildir/bar//
homeDirectory: /var/local/maildir
userPassword: {CRYPT}I.oaTeBKQv5j.
図3 メールの配送とLDAPの関係
|         incoming mail
|             |
|             |
|             V                                                     LDAPサーバ
|           exim                                                   |
|             |                                                    |
|         ldap_aliases                                             |
|         による配送先   ----------------------------------------->|
|         の検索         base dc=example,dc=jp                     |
|             |          search                                    |
|             |           mailLocalAddress=$local_part@example.jp  |
|             |          <-----------------------------------------|
|             |            mailアトリビュート                      |
|             |                                                    |
|             |                                                    |
|        address_directoryによりMaildirとして配送                  |
|             |                                                    |
|             |                                                    |
|             V                                                    |
|        /var/local/maildir/$local_part                            |
|             ^|                                                   |
|             ||                                                   |
|             ||                                                   |
|             |V                                                   |
|       mailアトリビュートで得られたディレクトリにアクセス         |
|             ^              homeDirectory, mail                   |
|             |              <-------------------------------------|
|             |                                                    |
|             |                    bindできるか?                   |
|         authldapによる認証 ------------------------------------->|
|             ^                    dc=example,dc=jp                |
|             |            mailLocalAddress=ログイン名@example.jp  |
|             |                                                    |
|        courier-imap
|             ^
|             | 
|             |
|          IMAP user

まず、スプールディレクトリを作成します。ここでは/var/local/maildirに全員のメールスプールを作ることにします。courier-imapで必要としているMaildir形式のディレクトリを作るにはcourier-imapパッケージについてくるmaildirmake.courier-imapコマンドを使います。それから実際のアカウントなしでメールのみを読むことになるので、これらのMaildirはlistユーザの所有にしてアクセス権限はlistユーザだけにしておきます。

mkdir /var/local/maildir
maildirmake.courier-imap /var/local/maildir/bar
chown -R list.list /var/local/maildir/bar

exim側の設定

exim側ではexim.confでリスト11のように設定しておきます。

リスト11 exim.confの設定抜粋
address_directory:
 driver = appendfile
 no_from_hack
 prefix = ""
 suffix = ""
 maildir_format

ldap_aliases:
 driver = aliasfile
 file_transport = address_file
 directory_transport = address_directory
 user = list
 search_type = ldapm
 query = "ldap:///dc=example,dc=jp?mail?sub?mailLocalAddress=$local_part@example.jp"

デフォルトではaddress_directoryはmaildir_formatが有効になってないのでこれを有効にします。これによりaliasでディレクトリを指定した時にそのディレクトリをMaildir形式として新規メールをスプールしていくことができるようになります。

次にldap_aliasesでLDAPの情報でメールの配送先を決めます。directory_transport = address_directoryをいれておくことでLDAPで引いてきた結果がディレクトリだと上で設定したようにaddress_directoryを使うことでそのディレクトリをMaildir形式として新規メールをスプールすることになります。user = list でMaildirのディレクトリの所有者を指定しています。これによりスプールに新規メールを書きにいく時にはlistユーザ権限で書きこみにいきます。queryにLDAPの検索方法を指定しておきます。

query = "ldap:///dc=example,dc=jp?mail?sub?mailLocalAddress=$local_part@example.jp"

このqueryはデフォルトのLDAPサーバ(localhost:389)にdc=example,dc=jpを検索ベースとしてmailLocalAddressが$local_part@example.jpであるディレクトリエントリを探してそのディレクトリエントリのmail属性を検索結果として使うということを意味しています。 このeximにbar@example.jp宛のメールがくれば、LDAPで図2のエントリが検索でひっかかって、そのmail属性の値/var/local/maildir/bar//が配送先に決定します。これはディレクトリなのでldap_aliasesのdirectory_transportで指定しているaddress_directoryの記述に従い/var/local/maildir/bar/にMaildir形式で新規メールをスプールします。この時ldap_aliasesでuser = listと指定しておいた通りlistユーザ権限で/var/local/maildir/bar/以下に書きこみにいきます。

このようにexim側の配送を設定します。

courier-imap側の設定

eximでメールを/var/local/maildir/以下に配送できるようにしても、これがユーザから読めるようになっていなければ意味がありません。ここでは例としてcourier-imapを使い、IMAPでアクセスできるようにしてみましょう。courier-imapにはauthldapをいうLDAPを使う認証モジュールがあるのでそれを使うことにします。

courier-imapのdebianパッケージを使っている場合、/etc/courier-imap.configでどの認証モジュールを使うかをAUTHMODULESで定義します。ここではLDAPによる認証を使うのでリスト12のようにAUTHMODULESにauthldapを指定します。

リスト12 courier-imap.configの設定
AUTHMODULES="authldap"

authldapの設定は/etc/courier-imap.authldaprcによりおこないます(リスト13)。

リスト13 courier-imap.authldaprcの設定
LDAP_SERVER	192.168.0.1
LDAP_BASEDN	dc=example,dc=jp
LDAP_AUTHBIND	1 
LDAP_MAIL	mailLocalAddress
LDAP_DOMAIN	example.jp
LDAP_GLOB_UID list
LDAP_GLOB_GID list
LDAP_HOMEDIR  homeDirectory
LDAP_MAILDIR  mail

IMAPでログインする時にそのユーザはどのディレクトリエントリに対応するかを決定するためにLDAP_MAIL属性が検索されます。IMAPでログインする時に、ユーザ名で@移行を付けなかった場合LDAP_DOMAINで指定したドメインが追加されて検索されます。LDAP_DOMAINを定義していない時はドメイン部分は*が追加されて検索されます。

つまりLDAPの検索式としては次のようになります。
  <LDAP_MAILで指定したアトリビュート>=<IMAP login名>@<LDAP_DOMAINの値>

IMAP login名に@が含まれている場合はLDAP_DOMAINによる補完はおこなわれなくて次のようになります。
  <LDAP_MAILで指定したアトリビュート>=<IMAP login名>

ここではLDAP_MAILをmailLocalAddress、LDAP_DOMAINをexample.jpにしているのでLDAPで次のように検索することになります。

mailLocalAddress=<IMAP login名>@example.jp

もしIMAPでbarでログインすると次のように検索します。

mailLocalAddress=<IMAP login名>@example.jp

bar@example.netでログインすると LDAP_DOMAINのexample.jpを無視して次のように検索します。

mailLocalAddress=bar@example.net

リスト13のようにcourier-imap.authldaprcに設定したあと/etc/courier-imap.configの最後のIMAPDSTARTをYESにして(IMAPDSTART=YES)から、/etc/init.d/courier-imap start で起動します。

postfixの場合

Debian 2.2にあるpostfixパッケージは古いのでまだLDAPサポートはありませんが、開発版の方ではLDAPサポートがついたpostfixになっています。最近のパッケージではpostfix-ldapというパッケージをインストールするとLDAPサポートが使えるようになります。これを使うとpostfixでもLDAPをaliasの一つとして使うことができるます(リスト14)。

リスト14 postfixのLDAPを使ったalias
alias_maps = hash:/etc/aliases, ldap:ldapsource

このようにldap:ldapsourceと記述することでldapsourceで記述される設定でLDAPからaliasを検索することができます。ここのldapsourceという文字列で、ここで使うLDAPの検索をどうするかを設定するパラメータのプレフィクスを決めます。ldap:ldapsourceとした場合ldapsourceではじまるパラメータが使われることになります。ldap:ldapaliasなどとするとldapaliasではじまるパラメータを使うことになるわけです。

ldap:ldapsourceだとするとLDAPに関するパラメータはリスト15のように/etc/postfix/main.cfで設定します。

リスト15 LDAPに関するパラメータ
ldapsource_server_host	= localhost
ldapsource_server_port	= 389
ldapsource_search_base	= dc=example,dc=jp
ldapsource_query_filter	= (mailLocalAddress=%s)
ldapsource_result_attribute = mail
ldapsource_scope = sub
ldapsource_bind	= yes
ldapsource_bind_dn = ""
ldapsource_bind_pw = ""