[ADSI] LDAP SSL あり / なしで ChangePassword() の設定可能文字数が異なる理由
皆様ごきげんよう。ういこです。案の定病んでしまい、昨日更新できませんでした…。
それにしても、Blog の View を見ていると、RSS でご覧頂いている方々と、Web 経由でいらっしゃる方々でくっきりとアクセス傾向が違うのが判ります。それによると、やっぱり大人気は VBScript - ADSI ネタ。私の 3 分間 Debugging はいまいちです。というわけで、今これまでの 2 つのデバッグネタの続きを書いてましたが長くなりそうなのでさくっとライトに久しぶりに ADSI ネタを行きたいなと。
もちろん Windbg ネタもちゃんと書きます!
【今日のお題】
パスワード変更時の文字数制限について
~ SSL を使用しない環境では ChangePassword() API を使っても
64 文字以上設定できないのはなぜ?
ちなみにこれは、過去にぶちあたった内容をもとにした記事となります。
◆ドメイン構成
ドメイン A … LDAP SSL 通信、証明書サービスがインストールされている。
ドメイン B … LDAP には SSL 未使用。証明書サービスもインストールされていない。
◆どんな動きか
ドメイン A |
ドメイン B |
|
SetPassword() |
64 文字以上設定可能 |
64 文字以上設定可能 (※1) |
ChangePassword() |
64 文字以上設定可能 |
64 文字以上設定するとエラー発生 (※2) |
(※1) いずれのドメインでも、SetPassword() だと 256 文字まで設定 OK
(※2) 0x8007052D 発生 (= -2147023571)
…確かに動作に違いがありますね。これはなぜか?
証明書サービスなのか、はたまた SSL がなせるわざか…。順番に見ていきましょう。
(1) パスワード変更時のプロトコルによって内部処理は分岐する
結論からいうと、キーポイントは ”SSL” です。
ADSI が提供する ChangePassword() を実行した際、ADSI は ChangePassword() が実行されたドメイン環境が LDAP SSL をサポートしているかどうかの確認を行います。
サポートの有無によって動作は上記のように異なることになるのです。
- LDAP SSL がサポートされていない場合
ChangePassword() は Windows OS が用意している既定のパスワード変更処理の機能 (NetAPI と呼ばれます) を用いてパスワードの変更を行います。
- LDAP SSL がサポートされている場合
ChangePassword() は LDAP 経由でパスワードの変更処理を行います。
まず、パスワード変更時のプロトコルを見ていきましょう。大別して以下の 6 つがあります。
- パスワード変更時プロトコル
1. NetUserChangePassword プロトコル
2. NetUserSetInfo プロトコル
3. Kerberos change-password プロトコル
4. Kerberos set-password プロトコル
5. Lightweight Directory Access Protocol (LDAP) write-password 属性 (※)
6. LAN Manager 互換の XACT-SMB
(※) 128-bit Secure Sockets Layer [SSL] 使用時のみ対象
今回の場合、ドメイン A では SSL が使用され、ドメイン B では SSL は使用されていません。つまり、ドメイン A では、上記プロトコルのうち、3. および 4. である [Kerberos change-password プロトコル] と[Kerberos set-password プロトコル] が使用されます。プロトコルが異なる場合、内部動作シーケンスは全く変わってしまうのです。
LDAP SSL は、ドメインに証明書サービスがインストールされている場合に使用可能となりますが、今回はドメイン A がそれに該当します。以下は Windows 2000 を対象にした文書ですが、 Windows Server 2003 もこれに該当します。
Description of password-change protocols in Windows 2000
https://support.microsoft.com/kb/264480/en-us
LDAP SSL が使用できない環境では、上記の通り 1.の Net 系API NetChangeUserPassword() API が使用されます。
Net 系 API は内部でバッファのサイズを 127 バイト固定値で持ちますが、今回のシナリオではドメイン B がこの影響を受けることになり、結果として63 文字までが設定範囲となるということになるのです。
(2) なぜ、バッファサイズが 127 バイトなのに、半角 63 文字が影響範囲になるの?
さて、NetAPI が使用されるということについてクリアになった後の素朴な疑問としては、「なんで 127 バイトバッファ取ってて、63 文字までしかだめなの?だって、半角数字と半角アルファベット使ってるよ? 」ということではないでしょうか。
これは、NetChangeUserPassword() API は、パスワード値として Unicode 文字列を扱うためなのです。
Windows Server 2003 では、Unicode 文字列を UTF-16 で扱います。UTF-16 は半角アルファベット、半角数字も 2 バイトとして扱うため、 127 バイト = 63 文字までという制限になるのです。
プラットフォーム SDK : NetUserChangePassword
https://msdn.microsoft.com/ja-jp/library/cc447014.aspx
上記のドキュメント中にも NetUserChangePassword は文字列を Unicode として扱う記載があります。
(3) ChangePassword() では 63 文字が限界なのに SetPassword() が 256 バイト可能だったがなぜか?
次に浮かぶ疑問としては、「ドメイン B でNet APIが使用されるのであれば、パスワード変更(ChangePassword() )では63文字で制限されるのにパスワード設定(SetPassword())が 256 バイトまで設定可能なのはなぜ?」 ではないでしょうか。
もう一度、上記の ADSI のSetPassword()、ChangePasword() の場合の、
プロトコルシナリオの差異について着目してみましょう。
- パスワード変更時プロトコル
1. NetUserChangePassword プロトコル
2. NetUserSetInfo プロトコル
3. Kerberos change-password プロトコル
4. Kerberos set-password プロトコル
5. Lightweight Directory Access Protocol (LDAP) write-password 属性 (※)
6. LAN Manager 互換の XACT-SMB
(※) 128-bit Secure Sockets Layer [SSL] 使用時のみ対象
この内容を踏まえて状況を改めて整理してみます。
(※) それぞれ、1. から 3. などの数字は試行される順番です。
例えば、1. のプロトコルを試行してその環境ではそのプロトコルはサポートされないと識別されると、次に 2. のプロトコルが試行されるといったような動作となります。
◆ SetPassword() のパスワード設定動作
1. 上記 5、LDAP SSL プロトコルで設定を試行
2. 上記 4、Kerberos SetPassword プロトコルで設定を試行
3. 上記2、NetUserSetInfo API で設定を試行
◆ ChangePassword() のパスワード変更動作
1. 上記 5、LDAP SSL プロトコルで設定を試行
2. 上記 1、NetUserChangePassword API で設定を試行
ドメイン B では SetPassword() 実行の際、LDAP SSL は使用できないものの、 Kerberos SetPassword は可能です。 通常、Kerberos SetPassword プロトコルの使用は内部で自動的に識別されるため、ユーザーもしくは開発者が意識する必要はありません。
この環境の場合、状況から、ドメインでの SetPassword() の場合はこのKerberos SetPassoword プロトコルで動作が完結し、NetUserSetInfo() の試行に至らないため結果としてパスワード設定時に 255 文字設定できているいう判断になりました。
***
なかなか奥深いですね。こういうとき、内部で何が呼ばれてるかチェックするのに、Windbg がとっても便利なので、是非試してみてください。
~ ういこう@そろそろ ILM ネタもやらなきゃなぁ ~