Download - Active Directoryデータの Security Descriptor
Active Directory データの Security Descriptor
nTSecurityDescriptor 属性の値を見やすく出力する
小山 三智男mitchin
2
Active Directory データのプロパティ出力
以前、 Active Directory データのプロパティ出力について紹介しました。
初期版http://www.slideshare.net/mitchin227/output-properties
" 大きい整数 " 対応版http://www.slideshare.net/mitchin227/large-integer
これをサンプルアプリに組み込めば出力できるようになります。
サンプルアプリとスライドはこちらhttp://blogs.wankuma.com/mitchin/archive/2013/12/08/328279.aspx
3
Security Descriptor って?
Security Descriptor とはセキュリティ記述子のことで、ざっくり言えばセキュリティ(アクセス権)設定を記述したものです。ここでは Active Directory オブジェクトに関連付けられたセキュリティ情報を保持するものです。この中に随意アクセス制御リスト( DACL : Discretionary Access Control List )やシステム アクセス制御リスト( SACL : System Access Control List )、所有者、プライマリ グループがあります。DACL はユーザやグループに対して 許可 / 拒否の権限を定義したアクセス規則であるアクセス制御エントリ( ACE : Access Control Entry )の集まりで、単にアクセス制御リスト( ACL )と呼ぶことがあります。SACL は監査規則である ACE の集まりです。
4
Windows Server 2008 で確認
管理ツール「 Active Directory ユーザとコンピュータ」で、「表示」メニューの「拡張機能」にチェックがついている状態で、ユーザやグループなどのプロパティを表示します。
5
セキュリティ タブで確認
セキュリティ タブを開きます。
ファイルやフォルダのアクセス権を設定する時もそのプロパティ画面のセキュリティ タブで行いますがこちらも同じです。画面もほぼ同じですね。
6
属性は nTSecurityDescriptor
属性エディタには表示されません。
7
nTSecurityDescriptor 属性の値の型は?
nTSecurityDescriptor 属性の値の型は ADSI の IADsSecurityDescriptor です。値をこのインターフェイスにキャストできます。
また、関連するアクセス制御リストのインターフェイスは IADsAccessControlList で、アクセス制御エントリのインターフェイスは IADsAccessControlEntry です。
他にもアクセス制御エントリに関連する次の列挙体があります。•ADS_RIGHTS_ENUM•ADS_ACEFLAG_ENUM•ADS_ACETYPE_ENUM•ADS_FLAGTYPE_ENUM
8
プログラムから確認するには
DirectoryEntry.Properties プロパティ( PropertyCollection クラス)からプロパティとその値( PropertyValueCollection クラス)を列挙して取得します。nTSecurityDescriptor 属性はオプションのプロパティ出力( OutputOptionalProperties )では取得できないので、通常のプロパティ出力( OutputProperties )の方だけ考慮します。※nTSecurityDescriptor は必須プロパティです。
サンプルコードは次の名前空間をインポートしています。•ActiveDs ( Active DS Type Library の参照設定が必要)•System.IO•System.Security.Principal•System.Text
9
初期版の出力
COM(ADSI) 未対応のため「 System.__ComObject 」と出力されています。
10
今回の出力
COM(ADSI) に対応した出力のサンプルです。
11
出力の書式
今回はセキュリティ記述子の随意アクセス制御リストの各アクセス制御エントリを 番号をつけて見やすい形で出力します。出力する項目は次の 5 つのプロパティです。
•Trustee (ユーザやグループの名前部分のみ)•AccessMask•AceFlags•AceType•Flags
これらの値順に重複は除外して出力します。また、 Trustee 以外は整数型ですが、値は 7 ページに記載した列挙体の値なので、値とそれを表す列挙値の文字列も出力します。※ この文字列の取得はメソッド化します。
12
通常のプロパティ出力の抜粋( VB )
Public Shared Sub OutputProperties( entry As DirectoryEntry, filePath As String) Dim props = entry.Properties.PropertyNames.Cast( Of String)().OrderBy(Function(s) s).ToList() ' プロパティ名のリスト Using writer As New StreamWriter(filePath, False, Encoding.UTF8) For Each pname In props ' プロパティ数分 Dim val = entry.Properties.Item(pname).Value If TypeOf val Is Byte() Then ' バイト配列の時 ' バイト値を取得して出力 ElseIf TypeOf val Is IADsSecurityDescriptor Then ' セキュリティ記述子の時 --> 次のページに記載 Else ' それ以外の時 ' 各値を取得して出力 End If Next End UsingEnd Sub
13
IADsSecurityDescriptor の出力( VB )Dim sd = DirectCast(val, IADsSecurityDescriptor)Dim aceGroups = DirectCast(sd.DiscretionaryAcl, IADsAccessControlList).Cast(Of IADsAccessControlEntry)().OrderBy( Function(ace) Path.GetFileName(ace.Trustee)).ThenBy( Function(ace) ace.AccessMask).ThenBy( Function(ace) ace.AceFlags).ThenBy( Function(ace) ace.AceType).ThenBy( Function(ace) ace.Flags).GroupBy( Function(ace) String.Format("{0}|{1}|{2}|{3}|{4}", ace.Trustee, ace.AccessMask, ace.AceFlags, ace.AceType, ace.Flags)).ToList() ' プロパティ値でグループ化した ACE Dim ctr = 0 writer.WriteLine(pname)
14
IADsSecurityDescriptor の出力( VB )For Each aceGroup In aceGroups 'ACE 数分 Dim ace = aceGroup.First() ctr += 1 writer.WriteLine(" {0:D2}. Trustee : {1}", ctr, Path.GetFileName(ace.Trustee)) writer.WriteLine(" {0:D2}. AccessMask : {1}", ctr, ToEnumValueText(ace.AccessMask, GetType(ADS_RIGHTS_ENUM))) writer.WriteLine(" {0:D2}. AceFlags : {1}", ctr, ToEnumValueText(ace.AceFlags, GetType(ADS_ACEFLAG_ENUM))) writer.WriteLine(" {0:D2}. AceType : {1}", ctr, ToEnumValueText(ace.AceType, GetType(ADS_ACETYPE_ENUM))) writer.WriteLine(" {0:D2}. Flags : {1}", ctr, ToEnumValueText(ace.Flags, GetType(ADS_FLAGTYPE_ENUM)))Next
15
列挙体のプロパティ値をテキスト化( VB )Private Shared Function ToEnumValueText( value As Integer , enumType As Type) As String If enumType Is GetType(ADS_ACETYPE_ENUM) Then 'AceType の時 Return String.Format("{0}({1})", value, [Enum].ToObject(enumType, value)) End If Dim selector = Function(e As Integer) [Enum].ToObject(enumType, e).ToString() Dim values = [Enum].GetValues(enumType).Cast( Of Integer)().Where(Function(e) (value And e) = e).OrderBy( selector).Select(selector).ToList() ' 設定されている値の列挙体文字列 If values.Count = 0 Then ' 設定されている値がない時 Return value.ToString() End If Return String.Format("{0}({1})", value, String.Join(" | ", values))End Function
16
通常のプロパティ出力の抜粋( C# )
public static void OutputProperties( DirectoryEntry entry, string filePath) { var props = entry.Properties.PropertyNames. Cast<string>().OrderBy(s => s).ToList(); // プロパティ名のリスト using (var writer = new StreamWriter(filePath, false, Encoding.UTF8)) { foreach (var pname in props) { // プロパティ数分 var val = entry.Properties[pname].Value; if (val is byte[]) { // バイト配列の時 // バイト値を取得して出力 } else if (val is IADsSecurityDescriptor) { // セキュリティ記述子の時 --> 次のページに記載 } else { // それ以外の時 // 各値を取得して出力 } } }}
17
IADsSecurityDescriptor の出力( C# )var sd = (IADsSecurityDescriptor)val;var aceGroups = ((IADsAccessControlList)sd.DiscretionaryAcl). Cast<IADsAccessControlEntry>().OrderBy( ace => System.IO.Path.GetFileName(ace.Trustee)).ThenBy( ace => ace.AccessMask).ThenBy( ace => ace.AceFlags).ThenBy( ace => ace.AceType).ThenBy( ace => ace.Flags).GroupBy( ace => String.Format("{0}|{1}|{2}|{3}|{4}", ace.Trustee, ace.AccessMask, ace.AceFlags, ace.AceType, ace.Flags)).ToList(); // プロパティ値でグループ化した ACE var ctr = 0; writer.WriteLine(pname);
18
IADsSecurityDescriptor の出力( C# )foreach (var aceGroup in aceGroups) { //ACE 数分 var ace = aceGroup.First(); ctr++; writer.WriteLine(" {0:D2}. Trustee : {1}", ctr, System.IO.Path.GetFileName(ace.Trustee)); writer.WriteLine(" {0:D2}. AccessMask : {1}", ctr, ToEnumValueText(ace.AccessMask, typeof(ADS_RIGHTS_ENUM))); writer.WriteLine(" {0:D2}. AceFlags : {1}", ctr, ToEnumValueText(ace.AceFlags, typeof(ADS_ACEFLAG_ENUM))); writer.WriteLine(" {0:D2}. AceType : {1}", ctr, ToEnumValueText(ace.AceType, typeof(ADS_ACETYPE_ENUM))); writer.WriteLine(" {0:D2}. Flags : {1}", ctr, ToEnumValueText(ace.Flags, typeof(ADS_FLAGTYPE_ENUM)));}
19
列挙体のプロパティ値をテキスト化( C# )private static string ToEnumValueText(int value, Type enumType) { if (enumType == typeof(ADS_ACETYPE_ENUM)) { //AceType の時 return String.Format("{0}({1})", value, Enum.ToObject(enumType, value)); }
Func<int, string> selector = e => Enum.ToObject(enumType, e).ToString(); var values = Enum.GetValues(enumType).Cast<int>().Where( e => (value & e) == e).OrderBy(selector).Select(selector).ToList(); // 設定されている値の列挙体文字列
if (values.Count == 0) { // 設定されている値がない時 return value.ToString(); } return String.Format("{0}({1})", value, String.Join(" | ", values));}
20
詳細や関連情報はブログ等で
Active Directory データのプロパティ出力http://blogs.wankuma.com/mitchin/archive/2013/09/19/328123.aspxhttp://blogs.wankuma.com/mitchin/archive/2013/09/20/328126.aspx
Active Directory データのプロパティ出力の COM 対応版http://blogs.wankuma.com/mitchin/archive/2013/12/04/328271.aspxhttp://blogs.wankuma.com/mitchin/archive/2013/12/05/328273.aspx
わんくま初 LThttp://blogs.wankuma.com/mitchin/archive/2013/12/08/328279.aspx※ スライド、サンプルコード、サンプルアプリのリンクがあります。
COM 対応版の変更点の説明(セキュリティ記述子: SecurityDescriptor )http://blogs.wankuma.com/mitchin/archive/2013/12/09/328281.aspx
COM 対応版の変更点の説明(大きい整数関連)http://blogs.wankuma.com/mitchin/archive/2013/12/06/328275.aspx
COM 対応版の変更点の説明(構造化例外処理を使わないで値がないかを確認)
http://blogs.wankuma.com/mitchin/archive/2013/12/10/328283.aspx