マイナーでもいいよね??

殆どVB系、でも .NET じゃない VB は知らないよん

目次

Blog 利用状況

書庫

日記カテゴリ

セキュリティ記述子(SecurityDescriptor)の出力の.NETクラス使用版(VB)

セキュリティ記述子(SecurityDescriptor)のADSIに対応する.NETのクラスを調べたので実装してみました。

Active Directoryデータのプロパティ出力のCOM対応版(VB)と比較しながら見ていただければと思います。

コードはサンプルアプリに組み込む前提で書いてます。

追加で System.Security.AccessControl 名前空間をインポートしてます。

 

説明は別途ということでまずはコードを。

最初は呼出し側。出力部分はメソッド化しました。

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   'プロパティ数分

      If pname.Equals("nTSecurityDescriptor") Then  'セキュリティ記述子の時

        writer.WriteLine(pname)

        OutputSecurityDescriptor(entry.ObjectSecurity, writer)  'セキュリティ記述子を出力

        Continue For

      End If

 

      Dim val = entry.Properties.Item(pname).Value

      If TypeOf val Is Byte() Then  'バイト配列の時

        Dim pstr = GetByteValue(pname, DirectCast(val, Byte()))   'バイト値を取得

        writer.WriteLine("{0}:{1}", pname, pstr)

      ElseIf TypeOf val Is IADsLargeInteger Then  '大きい整数の時

        Dim li = GetLargeIntegerValue(pname, DirectCast(val, IADsLargeInteger))  '大きい整数値を取得

        writer.WriteLine("{0}:{1}", pname, li)

      Else  'それ以外の時

        For Each pval In entry.Properties.Item(pname)   '値数分

          Dim value = GetValue(pval)   '値を取得

          writer.WriteLine("{0}:{1}", pname, value)

        Next

      End If

    Next

  End Using

End Sub

 

続いて出力処理側。DirectoryEntry.ObjectSecurityプロパティのとこに少し書きましたが、Trustee の名前部分(ユーザ名やグループ名)を取得する必要があるので、別途メソッド化しました。

'セキュリティ記述子を出力

Private Shared Sub OutputSecurityDescriptor(security As ActiveDirectorySecurity, writer As StreamWriter)

  Dim sd As New CommonSecurityDescriptor(True, True, security.GetSecurityDescriptorBinaryForm(), 0)

  Dim aceList = sd.DiscretionaryAcl.Cast(Of QualifiedAce)().ToList()

  Dim sidList = aceList.GroupBy(Function(ace) ace.SecurityIdentifier).Select(

    Function(group) group.First().SecurityIdentifier.Value).ToList()

  Dim sidNameDic = CreateSidNameDictionary(sidList)   'SID/アカウント名のコレクションを作成

  Dim aceGroups = aceList.OrderBy(Function(ace) sidNameDic.Item(ace.SecurityIdentifier.Value)).ThenBy(

    Function(ace) ace.AccessMask).ThenBy(Function(ace) ace.AceFlags).ThenBy(Function(ace) ace.AceType).ThenBy(

    Function(ace) If(TypeOf ace Is ObjectAce, DirectCast(ace, ObjectAce).ObjectAceFlags, 0)).GroupBy(

    Function(ace) String.Format("{0}|{1}|{2}|{3}|{4}",

      sidNameDic.Item(ace.SecurityIdentifier.Value), ace.AccessMask, ace.AceFlags, ace.AceType,

      If(TypeOf ace Is ObjectAce, DirectCast(ace, ObjectAce).ObjectAceFlags, 0))).ToList()  'プロパティ値でグループ化したACE

  Dim ctr = 0

  For Each aceGroup In aceGroups  'ACE数分

    Dim ace = aceGroup.First()

    ctr += 1

    writer.WriteLine(" {0:D2}. Trustee   :{1}", ctr, sidNameDic.Item(ace.SecurityIdentifier.Value))

    writer.WriteLine(" {0:D2}. AccessMask:{1}", ctr, ToEnumValueText(ace.AccessMask, GetType(ActiveDirectoryRights)))

    writer.WriteLine(" {0:D2}. AceFlags  :{1}", ctr, ToEnumValueText(ace.AceFlags, GetType(AceFlags)))

    writer.WriteLine(" {0:D2}. AceType   :{1}", ctr, ToEnumValueText(ace.AceType, GetType(AceType)))

    If TypeOf ace Is ObjectAce Then   'ディレクトリ オブジェクトに関連付けられたACEの時

      writer.WriteLine(" {0:D2}. Flags     :{1}", ctr,

        ToEnumValueText(DirectCast(ace, ObjectAce).ObjectAceFlags, GetType(ObjectAceFlags)))

    Else  'CommonAce(ACE)の時

      writer.WriteLine(" {0:D2}. Flags     :0", ctr)

    End If

  Next

End Sub

 

'SID/アカウント名のコレクションを作成

Private Shared Sub CreateSidNameDictionary(sidList As List(Of String)) As Dictionary(Of String, String)

  Dim sidNameDic As New Dictionary(Of String, String)(sidList.Count)

  Using root = GetRootEntry()   'ルートのDirectoryEntryを取得

    Using searcher As New DirectorySearcher(root)

      For Each sid In sidList   'SID数分

        searcher.Filter = String.Format("(objectSid={0})", sid)

        Dim res = searcher.FindOne()  '検索

        If res Is Nothing Then  '見つからなかった時(SYSTEM、SELF、Everyoneなど)

          Dim acc = New SecurityIdentifier(sid).Translate(GetType(NTAccount))   'アカウントに変換

          sidNameDic.Add(sid, Path.GetFileName(acc.Value))

        Else  '見つかった時

          Using entry = res.GetDirectoryEntry()

            Dim objectType = DirectCast([Enum].Parse(GetType(CategoryType), entry.SchemaClassName, True), CategoryType)

            If objectType = CategoryType.ForeignSecurityPrincipal Then  '外部のセキュリティプリンシパルの時

              Dim acc = New SecurityIdentifier(sid).Translate(GetType(NTAccount))   'アカウントに変換

              sidNameDic.Add(sid, Path.GetFileName(acc.Value))

            Else  '外部のセキュリティプリンシパル以外の時

              sidNameDic.Add(sid, entry.Properties.Item("cn").Value.ToString())

            End If

          End Using

        End If

      Next

    End Using

  End Using

  Return sidNameDic

End Function

 

最後に既存のメソッド。内部実装を変更しました。

'列挙体のプロパティ値をテキスト化

Private Shared Function ToEnumValueText(value As Integer, enumType As Type) As String

  If enumType Is GetType(AceType) 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 Object)().Select(Function(e) Convert.ToInt32(e)).Where(

    Function(e) (value And e) = e).OrderBy(selector).Select(selector).ToList()  '設定されている値の列挙体文字列

 

  values.Remove("None")

  If values.Count = 0 Then  '設定されている値がない時

    Return value.ToString()

  End If

  Return String.Format("{0}({1})", value, String.Join(" | ", values))

End Function

投稿日時 : 2013年12月24日 0:34

コメントを追加

# ZQHdAlVwFiBibLWE 2021/07/03 3:19 https://amzn.to/365xyVY

on other sites? I have a blog centered on the same information you discuss and would really like to

タイトル
名前
URL
コメント