さて、dsDoDirNodeAuthは第2引数で認証方式を指定し、適切なバッファを与えることで指定された認証方式にて認証を行う。例えばリスト6(auth_node2.c、11ページ目にも掲載)では、65行目で用意している認証方式の文字列をkDSStdAuthNodeNativeNoClearTextに変えることで、クリアテキスト形式以外のパスワード認証を用いるように指定している。

Mac OS XではAFPやSMBによるファイル共有、Mac OS X ServerではAPOPやPPTPやIPsecによるVPN、HTTPのBASIC認証やDigest認証などといった、プロトコルが独自に認証の方式を制定しているものがあるが、こうしたそれぞのプロトコルの持つ認証もOpen Directoryがまとめて行っており、パスワードの管理を一括することができている。例えば、「【特集】Mac OS X独自のディレクトリサービスOpen DirectoryとdsLocal(前編) - the inner universe of Leopard」で話のあったSMBのNTLM認証についてを試してみよう。

auth_ntlmv2.cがそのソースだ(リスト7、12ページ目にも掲載)。

なお、認証を行うためにはNTLMv2認証でのレスポンス値を実際に計算しなければならない。これについては高橋基信氏のWebサイトMONYO-COMにある「NTLM 認証プロトコルとセキュリティサポートプロバイダ」ページを参考に、ntlmv2.cを実装した(リスト8、13ページ目にも掲載)。

リスト7の121行目からのmain関数は、基本的には先のサンプルコードと同じだが、NTLMv2認証で必要なチャレンジ値やblobが定義されている(図10)。今回は検証のためのサンプルコードのためこうした値は定数で格納しているが、実際にはチャレンジ値は毎回生成を行うべきで、blobについても時刻やクライアントが生成するランダム値も正しい値を格納すべきである。

図10: リスト7「auth_ntlmv2.c」のmain関数部分

図10: リスト7「auth_ntlmv2.c」のmain関数部分

同じくリスト7の178行目、makeNTLMv2Responseでは、こうした値を元に、入力したパスワードを用いてNTLMv2のクライアントで計算、送付されるレスポンスを算出する(リスト7リスト8図11)。

図11: リスト8「ntlmv2.c」のmakeNTLMv2Response関数

図11:ntlmv2.cのmakeNTLMv2Response関数。レスポンス値の計算に用いられるのはパスワードそのものではなく、パスワードのMD4でのダイジェスト値であることに注意。このため、NTLMv2のレスポンスを作るには、チャレンジ、ユーザ名、ドメイン名、blobといった秘密でない情報と、パスワードのMD4値さえあれば可能となる

179行目のDoNTLMv2Authは、先のサンプルのDoTinyAuthのNTLMv2認証対応版だ(リスト7図12)。この関数は17行目から用意されており、認証用のバッファを確保した後に、以下の順序でバッファにデータを格納する。

  1. Open Directoryでのユーザ名
  2. サーバの生成したチャレンジ値
  3. クライアントから送付されたレスポンス値
  4. NTLMv2認証で用いられたユーザ名
  5. SMBでのドメイン名

1と4は通常同じ値になるが、何らかのマッピングでMac OS X (Open Directory)でのユーザ名とSMBでのユーザ名が異なる場合に4の値を変えることで対応を行う。

図12: リスト7のDoNTLMv2Auth関数

図12: リスト7のDoNTLMv2Auth関数

認証方式にkDSStdAuthNTLMv2を指定し、このバッファをdsDoDirNodeに渡すことで、DirectoryServiceの内部、dsLocalの場合はdsLocalのプラグインが、Mac OS XでOpen DirectoryのLDAPによるアカウント管理を行っている場合はApplePasswordServerの中で、与えられた情報および自身の格納するユーザのパスワードを使ってNTLMv2のダイジェストの計算が行われ、クライアントからのレスポンスと比較、認証の成否を判断する。

チャレンジ=レスポンス形式の認証の場合、確かに通信路には生パスワードが流れることはないが、一方サーバ側ではレスポンスの計算のため生パスワードをどこかに格納しなければならない。従来はAPOPやSMTP-Auth、SMB(Samba)など、それぞれが独自のパスワードデータベースを持ち、管理面からもセキュリティ面から見てもあまり好ましくない状態が続いていたが、Open Directoryは著名な認証方式を組み込むことで、認証そのものをそうしたサービスから切り離し、1つのパスワードデータベースで安全に格納することを実現している。

例えば、Mac OS Xに搭載されているSambaでは、samba/source/auth/auth_odsam.csamba/source/lib/opendirectory.csamba/source/passdb/pdb_odsam.cといったソースを確認してもらえば分かるように、単にOpen Directoryに認証を依頼するだけとなっており、tdbやsmbpasswdといった独自のパスワードデータベースを持たないようになっている。

これがdsLocalとShadowHashでどのように格納されているかは、「【特集】Mac OS X独自のディレクトリサービスOpen DirectoryとdsLocal(前編) - the inner universe of Leopard」で述べた通りだ。

                 ***

以上が、DirectoryService APIを用いた情報の取得と認証の方式だ。実際に編集操作を行う場合は、dsDoDirNodeAuthの第3引数をfalseにした上で認証を行い、そのアカウントの権限を取得した上で編集系のAPIを利用してattributeやrecordを追加する。また、DirectoryServiceに対するプラグインを作成することで、nodeの追加も可能となっている。

ただ、上記に述べたようにこれらのAPIはかなり煩雑である。旧Mac OS由来のAPI以外で、ここまで煩雑なものは他に例がなく、なぜこのようなAPIをMac OS Xで作ったのかは理解に苦しむ(NetInfoのAPIは、シンプルで比較的扱いやすいものであった。仮にNeXT由来ならば、そのAPIを拡張する形で実装するであろう)。

最後に繰り返すが、DirectoryServiceのAPIを用いて何かを実装するのはリスクが伴う行為であり、だいたいの選択肢がある限りは避けるのが正解であろう。