ShadowHashと同じく、dsLocalのアカウント情報も/var/db
以下に格納される。これはその名の通り/var/db/dslocal
というディレクトリになる(図16)。
このdslocalディレクトリの下にはdsmappings、indices、nodesという3つのディレクトリが存在する(実行例8)。nodesから順番に見てみよう。
実行例8: dsLocalのアカウント情報は、/var/db/dslocalというディレクトリに格納される
# cd /var/db/dslocal
# ls -l
total 0
drwxr-xr-x 4 root wheel 136 10 12 2007 dsmappings
drwxr-xr-x 3 root wheel 102 12 9 2007 indices
drwxr-xr-x 3 root wheel 102 10 12 2007 nodes
nodesでは、実際の情報がplist形式で格納されている。/var/db/nodes/Defaults
ディレクトリ配下には、aliasesやusers、machinesといったディレクトリが存在する。これらは、かつて/etc
以下にファイルとして置かれていたデータと同等のものだ(実行例9)。
実行例9: /var/db/nodes/Defaultsディレクトリ配下には、aliasesやusers、machinesといったディレクトリが存在する
# cd /var/db/dslocal
# ls -l
total 0
drwxr-xr-x 4 root wheel 136 10 12 2007 dsmappings
drwxr-xr-x 3 root wheel 102 12 9 2007 indices
drwxr-xr-x 3 root wheel 102 10 12 2007 nodes
# cd nodes
# ls
Default
# cd Default/
# ls
aliases config groups machines networks users
# cd users/
# ls
_amavisd.plist _devdocs.plist _pcastagent.plist _svn.plist _xgridcontroller.plist
_appowner.plist _eppc.plist _pcastserver.plist _teamsserver.plist agih.plist
_appserver.plist _installer.plist _postfix.plist _tokend.plist daemon.plist
_ard.plist _jabber.plist _qtss.plist _unknown.plist ldap.plist
_atsserver.plist _lp.plist _sandbox.plist _update_sharing.plist nobody.plist
_calendar.plist _mailman.plist _securityagent.plist _uucp.plist root.plist
_clamav.plist _mcxalr.plist _serialnumberd.plist _windowserver.plist test.plist
_cvs.plist _mdnsresponder.plist _spotlight.plist _www.plist
_cyrus.plist _mysql.plist _sshd.plist _xgridagent.plist
dsclで見えていた情報は、実際にはこうしたディレクトリであり、実際のレコードはplist形式のファイルとして格納されている(リスト1)。
リスト1 実際のレコードはplist形式のファイルとして格納されている
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>_writers_LinkedIdentity</key>
<array>
<string>me</string>
</array>
<key>_writers_hint</key>
<array>
<string>me</string>
</array>
<key>_writers_jpegphoto</key>
<array>
<string>me</string>
</array>
<key>_writers_picture</key>
<array>
<string>me</string>
</array>
<key>authentication_authority</key>
<array>
<string>;Kerberosv5;;me@LKDC:SHA1.5E52FEC5EB1FB35489AC7027FFD8439124DFF9A9;LKDC:SHA1.5E52FEC5EB1FB35489AC7027FFD8439124DFF9A9;</string>
<string>;ShadowHash;HASHLIST:<SALTED-SHA1,SMB-NT></string>
</array>
<key>generateduid</key>
<array>
<string>DBAB71C1-3475-4A67-8FDF-1B8221FC9E04</string>
</array>
<key>gid</key>
<array>
<string>501</string>
</array>
<key>home</key>
<array>
<string>/Users/me</string>
</array>
<key>jpegphoto</key>
<array>
<data>
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAICAgICAQICAgICAgIDAwYEAwMD
AwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0ODg4OCQsQEQ8OEQ0ODg7/
……
……
……
jbcArDJDFSdwJIPJwGIPOtLLpWhpCPEPgfRlR5Jkg0PSHumWRlH7wMVQIMk8
YIGVznBymnS6DPcRXEc+vanqs0hmhudWLrbryMExhn3rtx8pwRwSvXFIR//Z
</data>
</array>
<key>name</key>
<array>
<string>me</string>
</array>
<key>passwd</key>
<array>
<string>********</string>
</array>
<key>picture</key>
<array>
<string>/Library/User Pictures/Animals/Dragonfly.tif</string>
</array>
<key>realname</key>
<array>
<string>Machine Owner</string>
</array>
<key>shell</key>
<array>
<string>/bin/bash</string>
</array>
<key>uid</key>
<array>
<string>501</string>
</array>
</dict>
</plist>
XMLテキストであるplistでは検索性に劣る。このためデータそのものであるplist以外に検索用のインデックスとなる情報が、先の3つのディレクトリのうちの1つであるindicesディレクトリには格納されている。情報の検索についてはまずこのindecesディレクトリのインデックスを使って行い、それからnodesの下の実際のデータにアクセスするという手順になっている模様だ。
indecesディレクトリには、nodeと同じくDefaultディレクトリがあり、その下にindexというファイルが1つだけ置かれている(実行例10)。
実行例10: indecesディレクトリ配下のDefaultディレクトリには、indexというファイルが1つだけ置かれている
# cd /var/db/dslocal/indices/
# ls
Default
# cd Default/
# ls -l
total 120
-rw-r--r-- 1 root wheel 59392 7 23 20:05 index
このindexというファイルはsqlite3のデータベースであり、sqlite3コマンドを利用することで読み取りが可能だ(実行例11)。
実行例11: indexというファイルはsqlite3のデータベースで、sqlite3コマンドを利用し読み取り可能
# cd /var/db/dslocal/indices/
# cd Default/
# sqlite3 index
SQLite version 3.5.8
Enter ".help" for instructions
sqlite> select * from "dsAttrTypeStandard:RecordName" where value = "me" ;
me.plist|users|me
me.plist|groups|me
sqlite3コマンドでindexファイルを読み込み、.tablesコマンドでテーブル一覧をとると、先のnodesディレクトリにあったのと同じusers、groups、computersといったテーブルや、dsAttrTypeStandard:GeneratedUIDなどといったplist内部の属性情報ごとのテーブルがある(表2)。
表2については、スキーマ、データ例も含めたバージョンを「list2_dslocalschema.pdf」として用意しています
表2: plist内部の属性情報テーブル
名前 | 役割 |
---|---|
users | 各ユーザのplistファイルとその更新時間を記録 |
groups | 各グループのplistファイルとその更新時間を記録 |
computers | 各コンピュータのplistファイルとその更新時間を記録 |
dsAttrTypeStandard:RealName | レコードの形式(ユーザ、グループ、コンピュータ)と、そのReal name (フルネームなど長い名称)から、対応するplistファイル名を取得するためのテーブル |
dsAttrTypeStandard:GeneratedUID | レコードの形式(ユーザ、グループ、コンピュータ)と、各情報に一意に対応するUUIDから、対応するplistファイル名を取得するためのテーブル |
dsAttrTypeStandard:RecordName | ユーザやグループのレコードの形式および名称(アカウント名など短い名称)から対応するplistファイル名を取得するためのテーブル |
dsAttrTypeStandard:GroupMembers | グループに所属するユーザのGeneratedUID(UUID)から対応するグループのplistファイル名を取得するためのテーブル |
dsAttrTypeStandard:UniqueID | UIDから対応するユーザのplistファイルを取得するためのテーブル |
dsAttrTypeStandard:Member | アカウント名から所属するグループのplistファイル名を取得するためのテーブル |
dsAttrTypeStandard:PrimaryGroupID | GIDから対応するグループのplistファイル名を取得するためのテーブル |
例えば、dsAttrTypeStandard:GeneratedUIDではplistのファイル名と、userあるいはgroupなどといったレコードのタイプ、そしてUUIDが記録されている。UUIDにはインデックスが張られており、高速に検索が可能だ。これにより、nodesディレクトリ以下のplistを見て回らなくても、特定の情報から高速に対応するplistファイルや頻繁に使われる情報を取り出せる。
3つのディレクトリのうちの最後の1つ、dsmappingディレクトリにはAttributeMappings.plistとRecordMappings.plistという2つのplistが存在し、Open Directoryで正規化された設定名(例: dsAttrTypeStandard:RealName)と、plistでの短く分かりやすい名称(例: realname)との関連付けの情報が格納されている(図17)。
![]() |
図17: dsmappingsの例: これはRecordMappingsの例で、Open Directoryの各レコードを格納したフォルダがdsLocalのどのフォルダに対応するかを記述している。同様にAttributeMappingsがあり、こちらはOpenDirectoryの各属性名が、plistの中のどのキーに対応するか関連付ける |
dsclのようなDirectoryService APIを用いるアプリケーションからdsAttrTypeStandard:RealNameという名前で参照された情報は、このテーブルで読み替えられ、実際にはrealnameという名称で格納されている情報がアクセスされる。
なお、こうした関連付けはdsLocalに限らず、LDAPのディレクトリサービスを利用する場合でも用いられている。そもそもユーザ情報を登録するディレクトリのノードの名称や、それぞれの属性の名称といったキーワードはディレクトリサービスごとでまちまちだ。Open Directoryではあえて正規化された名称を用意し、ディレクトリサービスごとにマッピングを行い関連付けることで、どのディレクトリでもDirectoryService APIでは同じ正規化された名前で参照できるように工夫されている。
なお、今回は仕組みを説明するためにあえてファイルそのものへの直接アクセスを行ったが、dsLocalへのアクセスはもちろんこのような無理矢理な方法で行うべきではない。ましてやシステムの稼働中にdsLocalやShadowHashの情報の編集を行ってしまうと、まず間違いなくメモリ上にキャッシュされた情報と齟齬を起こし、最悪Mac OS Xそのものの稼働に支障を来してしまう。こうした情報へのアクセスはdsclなどのツールを利用する、あるいはOpen DirectoryのAPIであるDirectoryService APIを利用して行うべきである。
推奨されるのはdsclやシステム環境設定のアカウントパネル、Mac OS X Serverならば一連のサーバ管理ツールなどの、Appleがすでに提供しているツールを利用することだ。
他に選択肢がある限りDirectoryService APIを利用すべきではない。残念ながら、DirectoryService APIは非常に出来が悪く、生のまま使うのは耐え難い代物であるからだ。
『Mac OS X独自のディレクトリサービス「Open Directory」とdsLocal(後編) - the inner universe of Leopard』ではDirectoryService APIを使ってみるが、あくまで参考にとどめてほしい。