IPアドレスの指定に対応する
前ページで示したConvertNameToSidでリモートコンピュータのSIDを取得したいと考えた場合、その呼び出し方は次のようになるでしょう。
// szComputerは、リモートコンピュータの名前が格納されているものとする。
ConvertNameToSid(szComputer, szComputer, pSidComputer);
リモートコンピュータの名前が不正でなければ、恐らく関数は成功し、そのコンピュータのSIDを取得できます。しかし、ここで少し問題なのは、あらかじめリモートコンピュータの名前を知っておかなければならないという点です。これは当たり前のように思えるかもしれませんがそうとも限りません。例えば、コンピュータはIPアドレスでも表現できますし、現にLookupAccountNameやLookupAccountSidの第1引数はIPアドレスの指定に対応しています。しかし、第1引数にIPアドレスを指定したとしても、第2引数のアカウント名はどうするのかという問題が浮上します。ここには、リモートコンピュータ上のアカウントを指定するわけですから、結局、リモートコンピュータ上のアカウントを把握していなければならないように思えます。
ビルトインアカウント
「ビルトインアカウント」とはどのシステムにも存在するアカウントのことで、AdministratorやGuestアカウントなどが代表的です。これらのアカウントのSIDも一般のアカウントのようにコンピュータのSIDをベースにしており、RIDはそれぞれ、500、501と固定です。従って、ConvertNameToSidの第2引数にAdministratorを指定すれば、AdministratorのSIDを取得することができます。このSIDはコンピュータのSIDをベースにしているため、コンピュータのSIDを間接的に取得できたのと同じ意味を持つのです。
// szComputerは、IPアドレスで初期化されていても問題ない。 ConvertNameToSid(szComputer, TEXT("Administrator"), &pSid);
関数が成功すると、pSidはコンピュータのSIDと500のRIDで構成されます。この500を他の値に置き換えてLookupAccountSidを呼び出していけば、コンピュータ上のアカウントを列挙することができます。
CreateWellKnownSidを呼び出します。RIDを置き換える
次のコードは、サンプルプログラムのEnumAccountの内容と酷似しています。pSidのRIDを置き換えることにより、別のアカウントのSIDを完成させています。ConvertSidToNameという自作関数は、内部でLookupAccountSidを呼び出しています。
dwSubAuthorityCount = *GetSidSubAuthorityCount(pSid); for (i = 500, j = 0; i < 1050; i++) { *GetSidSubAuthority(pSid, dwSubAuthorityCount - 1) = i; if (ConvertSidToName(szComputer, pSid, szAccount, sizeof(szAccount), NULL)) MessageBox(NULL, szAccount, TEXT("アカウント"), MB_OK); }
GetSidSubAuthorityCount関数は、SIDのサブ機関値の数を格納するメモリのアドレスを返します。GetSidSubAuthorityは、サブ機関値のアドレスを返します。サブ機関値は配列のように考えることができ、例えばdwSubAuthorityCountが3であれば、GetSidSubAuthorityの第2引数は0から2までの数字を指定できます。RIDは最後のサブ機関値なので、インデックスはdwSubAuthorityCount - 1となります。for文の開始が1000ではなく500となっているのは、ビルトインアカウントのAdministratorやGuestも列挙するためです。アカウントの数は予測できないため、とりあえず1050としています。これにより、51番目に作成されたアカウントまでは列挙できることになります。
EnumAccountですが、その他の関数についても簡単に説明しておきます。DrawSidsという関数は、取得したSIDをテキスト形式で表示します。この関数が呼び出すConvertSidToStringSidは第1引数のSIDを基に、Sで始まるテキスト形式のSIDを第2引数に返します。ConvertSidToStringSidを使うには、_WIN32_WINNT 0x0500という定義と「sddl.h」のインクルードが必要になることに注意してください。また、GetComputerSidはアカウントのSIDからRIDを省いてコンピュータのSIDを完成させています。このSIDが最終的にLookupAccountSidに指定されることにより、コンピュータ名が取得されます。コンピュータをIPアドレスで識別しているのにも関わらず、コンピュータ名が表示されるのは、この関数の働きによるものです。なお、リモートコンピュータのアカウントを列挙する場合は、ネットワークの接続が必要となります。このとき、ファイアウォール系の機能が有効であると、アカウントの列挙に失敗することがあるので注意してください。最後に
最後に、システムがアカウントをアカウント名ではなくSIDで表す理由について考えてみます。これは、アカウントの実体がSIDで表されているからではないかと思われます。アカウントを作成するとき、そのアカウントのためにSIDが割り当てられますが、作成後にアカウント名を変更してもSIDは変化することはありません。例えば、Administratorという名前を変更したとしても、システムからはコンピュータの管理者を容易に特定できます。それは、システムが管理者をAdministratorという名前ではなく、RIDが500であるSIDとして解釈しているからです。アカウント名というのは、私達がSIDを識別しやすくするために付けたもので、システムから見ればどのような名前であるかは重要ではありません。
参考資料
- 『インサイドMicrosoft Windows 第4版(下)』 David A. Solomon・Mark E. Russinovich 原著、豊田孝 翻訳、日経BPソフトプレス、2005年10月
- EternalWindows 『セキュリティ / アクセスコントロール』
