Printout Header
RSS Feed

Active Directory Berechtigungen : Security Descriptors


In diesem Artikel des SelfADSI Tutorial wird erkl?rt, wie man per Script Berechtigungen auf Active Directory Objekte ausliest oder setzt. Folgende Abschnitte stehen zur Verfügung:

Der interne Aufbau eines Security Descriptors (S20
Rechtevererbung
Access Control Lists (ACLs)
AD Berechtigungen auslesen im Script
Access Control Entries (ACEs)
AD Berechtigungen setzen im Script
Control Flags im SD Header
AD Berechtigungen löschen im Script
Flags innerhalb von ACEs
Liste der Berechtigungen - Access Mask Bits innerhalb von ACEs
 
Object Type GUIDs innerhalb von ACEs
 
Inherited Type GUIDs innerhalb von ACEs
Trustees innerhalb von ACEs



Berechtigungen im Active Directory werden durch so genannte Security Descriptoren definiert, die als Eigenschaften bei den Objekten selbst abgespeichert werden. Zwei Active Directory Attribute sind intern als Security Descriptor aufgebaut:

nTSecurityDescriptor
Alle Objekte Hier werden die Berechtigungen f?r das Objekt selbst gespeichert. Jedes Objekt hat einen eigenen Security Desriptor.
msExchMailboxSecurityDescriptor
Postfach-Benutzer Diese Eigenschaft existiert nur in Microsoft Exchange-Umgebungen bei Benutzern mit Postfach. Es wird festgelegt, wer auf das betreffende Postfach zugreifen darf - allerdings nur zum Zeitpunkt der Erstellung des Postfachs. Sp?ter werden Postfachrechte nur durch dieses Attribut repr?sentiert, k?nnen jedoch nicht dar?ber gesetzt werden.


Der grundlegende LDAP Attribut-Datentyp für derartige Attribute ist eine Microsoft-proprietäre LDAP Attribut Syntax, die String(NT-Sec-Desc) genannt wird - grundsätzlich handelt es sich dabei um binäre Daten, jedoch kann auf den Inhalt eines Security Descriptors von Scripts aus zum Glück durch die ADSI-Schnittstellezugegriffen werden. Die entsprechenden Objekte werden in der ADSI Referen genau beschrieben:

Doch bevor wir uns mit dem Auslesen und Setzen von Berechtigungen im Active Directory durch Scripting besch?ftigen, sollten wir einen Blick auf die internen Strukturen eines Security Descriptors werfen. Der genau allgemeine Aufbau eines Security Descriptor Wertes wird in diesen Microsoft Dokumenten beschrieben:

Hinweis: Security Descriptor Strukturen findet man nicht nur bei den Berechtigungen f?r Verzeichnisobjekte, sondern auch bei Rechten im NTFS Filesystem, bei Registry-Rechten und ?berhaupt bei allen Berechtigungen auf Systemobjekte (Dienste, Drucker usw.). Dieser Artikel konzentriert sich jedoch auf die Besonderheiten der Rechte im Active Directory, dies betrifft vor allem den Aufbau von ACEs und von Access Masks.


Der interne Aufbau eines Security Descriptors (SD)

Die interne Struktur eines Security Descriptors ist ziemlich komplex, weil wir verschiedene Elemente beachten müssen, die ineinander verschachtelt sind: Der Security Descriptor als Ganzes besteht aus einem Header, den Owner-Informationen, und aus zwei verschiedenen Acces Lists (ACLs). Von diesen ACLs sind die eigentlichen Berechtigungen in der Discretionary ACL (DACL) enthalten, dieses wiederum besteht aus einzelnen Access Control Entries (ACEs). Von diesen ACEs gibt es viele verschiedene Typen, von denen für uns vier relevant sind.

Ein Active Directory Security Descriptor


Bei der Erstellung von Scripts bedeutet das Folgendes: Will ein Script die Rechte eines Active Directory Objektes auslesen, so muss es zuerst den Security Descirptor und die darin enthaltene DACL lesen, um an die Liste der ACEs zu kommen. In diesem ACEs stehen die konktreten Berechtigungen. Wenn man Rechte setzen will, so wird man selten einen Security Descriptor aus dem nichts heraus selbst aufbauen m?ssen - es gibt schlie?lich kein AD Objekt, dass nicht bereits mit Berechtigungen konfiguriert ist. Sofort nach der ergeben sich die Berechtigungen automatisch aus der Vererbung den den Voreinstellungen. Rechte zu vergeben oder wegzunehmen beruht also in Scripts stets auf der Ver?nderung der Liste der ACEs.

Betrachten wir zun?chst den Security Descriptor mit seinem Aufbau aus Header, Owner-Information und ACLs. Wie schon oben erw?hnt findet man eine genaue Beschreibung des technischen Aufbaus eines Security Descriptors im Microsoft Technet:

Struktur des Security Descriptors

Header: Eine Struktur, die eine allgemeine Revisionsnummer beinhaltet sowie verschiedene Control Bits. Diese Flags geben Auskunft dar?ber wie und aus welchen Bestandteilen der betreffende Security Descriptor zusammengesetzt ist - oder zusammengesetzt wird, falls man mit der Struktur gerade einen neuen Secruity Descriptor erzeugen will. Au?erdem bestimmen die Control Flags, ob die Berechtigungen und Audit-einstellungen von dar?ber liegenden Strukturen vererbt wurden, oder ob die Vererbung bei diesem Security Descriptor unterbrochen wird. Ansonsten sind im Header rein technisch noch Offset-Adressen enthalten, damit klar ist, an welcher Byte-Stelle die anderen Security Descriptor Bestandteile beginnen.

Owner: Der Objekt Owner - technisch in Form einer SID (Security Identifier). Der Owner ist derjenige Benutzer-Account, der das betreffende Objekt erzeugt hat. Der Owner darf stets die Berechtigungen auf das Objekt ?ndern. Eine Besonderheit: Erstellt ein Mitglied der vordefinierten Gruppe der Administratoren ein Objekt, so wird als Owner diese Gruppe eingetragen. Beim Setzen des Feldes im eigenen Script kann man übrigens auch direkt einen Windows-Anmeldenamen verwenden, z.B. "SELFADSI\pfoeckel".

Owner Group: Die Gruppe des Objekt Owners - technisch in Form einer SID (Security Identifier). Die Owner Group wird in der Praxis selten verwendet, meist spielt lediglich der Owner eine Rolle - Die Owner Group ist dann einfach die Prim?re Gruppe des Owners.

SACL - System Access Control List: Die SACL ist die Liste, in der die Auditing-Einstellungen des betreffenden Objektes gespeichert werden (Welche Zugriffe von wem werden wie ?berwacht?). Nur wer ?ber das Richtlinien-Privileg "Manage Auditing and Security Log" auf den Dom?nencontrollern verf?gt, kann die SACL  lesen oder schreiben. Bedenken Sie auch, dass es dar?ber hinaus immer noch globale Audit-Flags gibt, die f?r das Directory Service Auditing auf einem Dom?nencontroller aktiv sein m?ssen (wird ?ber GPO gesteuert).

DACL - Discretionary Access Control List: Die DACL enth?lt die Zugriffsberechtigungen auf ein Objekt (Wer darf was machen?). Dies ist die eigentlich Rechteliste. Ver?ndert werden darf sie stets vom Owner des Objektes und von allen, die die Berechtigung WRITE_DAC (siehe Liste der Access Masks Bits) auf das Objekt haben. Zum Auslesen der Discrentionary Access Control reicht die Berechtigung READ_CONTROL.


Access Control Lists (ACLs)

Eine Access List (egal ob System ACL f?r das Auditing oder eine Discretionary ACL f?r die Berechtigungen) besteht immer aus einem Header und beliebig vielen Acces Control Entries (ACEs). Der genaue technische Aufbau einer ACL wird hier beschrieben:

Struktur einer Access Control List

Zu beachten ist, dass der Revisions-Wert bei einer Active Directory ACL stets 4 sein muss. Die ACEs sind dann sozusagen die einzelnen Berechtigungen, die wir in der normalen administrativen Verwaltung sehen:

Access Control Lists in der GUI


Access Control Entries (ACEs)

Ein ACE ist die Festlegung einer einzelnen Berechtigung (oder Rechte-Verweigerung) f?r einen bestimmten Benutzer oder eine bestimmte Gruppe. Es gibt eine Menge unterschiedlicher Typen von ACEs, wobei f?r Active Directory Berechtigungen nur vier verschiedene Typen von Bedeutung sind, jeweils zwei f?r die Vergabe und die Verweigerung von Rechten. Der genaue technische Aufbau eines ACEs wird hier beschrieben:

Es existiert hier eine einfache ACE-Form, bei der Rechte auf das gesamte Obekt vergeben/entzogen werden inklusive Standard-Vererbung. Es gibt dann noch die komplexere Form des so genannten Object ACEs. In folgenden F?llen reicht n?mlich die einfache Form eine ACEs nicht aus:

Die vier f?r uns relevanten ACE-Typen im Detail:

Access Allowed ACE:

Access Allowed ACE

Bei diesem ACE ist der Typ immer auf 1 zu setzen. Er ist gedacht f?r einfache Rechtevergabe auf das gesamte Objekt. Die ACE Flags bestimmen, ob es sich hierbei um ein vererbtes Recht oder ein explizit vergebenes Recht handelt. Ein Berechtigung des ACE Types 0 wird stets auf untergeordnete Objekte weitervererbt.


Access Allowed Object ACE:

Access Allowed Object ACE

Bei diesem ACE ist der Typ immer auf 5 zu setzen. In diesem Object ACE k?nnen sowohl spezielle Rechte oder eingeschr?nkte Rechte z.B. nur f?r bestimmte Attribute vergeben werden (=> Object Type GUID) als auch eine spezielle Vererbung konfiguriert werden, so dass nur bestimmte Objektklassen diese Recht erben, oder dass das Recht nur auf das Objekt selbst gilt und nicht weiter vererbt wird (=> Interhited Type GUID). Das Flags-Feld gibt an, ob ein Object Type oder ein Inherited Type oder beides im ACE vorkommt.


Access Denied ACE:

Access Denied ACE

Bei diesem ACE ist der Typ immer auf 1 zu setzen. Er ist gedacht f?r einfache Rechteverweigerungen auf das gesamte Objekt. Die ACE Flags bestimmen, ob es sich hierbei um einen vererbten Eintrag oder eine explizit vergebene Verweigerung handelt. Ein Verweigerung des ACE Typs 5 wird stets auf untergeordnete Objekte weitervererbt.

 

Access Denied Object ACE:

Access Denied Object ACE

Bei diesem ACE ist der Typ immer auf 6 zu setzen. In diesem Object ACE k?nnen sowohl spezielle Rechte oder eingeschr?nkte Rechte z.B. nur f?r bestimmte Attribute verweigert werden (=> Object Type GUID) als auch eine spezielle Verweigerungen konfiguriert werden, so dass nur bestimmte Objektklassen diesen Eintrag erben, oder dass der Eintrag nur auf das Objekt selbst gilt und nicht weiter vererbt wird (=> Interhited Type GUID). Das Flags-Feld gibt an, ob ein Object Type oder ein Inherited Type oder beides im ACE vorkommt.


Control Flags im SD Header

Der Header eines Security Descriptors enthält die so genannten Control Flags. Viele der Flags spielen beim Umgang mit normalen Active Directory Berechtigungen keine Rolle. Der genaue Aufbau der Control Flags wird hier beschrieben:

Wenn man einen Security Descriptor liest, dann spielen folgende Flags eine Rolle

Control Flag Bitwert Bedeutung
DACL_AUTO_INHERITED 1024 Der Security Descriptor wurde durch normale Vererbung erzeugt.
DACL_PROTECTED 4096 Der Security Descriptor übernimmt/erbt NICHT die Berechtigungen von übergeordneten Objekten. Ist dieses Flag gesetzt, wurde also die Rechtevererbung für das betreffende AD Objekt deaktiviert.

 

Wenn man einen Security Descriptor schreibt oder neu erzeugt, dann spielen folgende Flags eine Rolle

Control Flag Bitwert Bedeutung
OWNER_DEFAULTED 1 Die Owner-Information wird automatisch gebildet. Man kann mit diesem Flag einen neuen Security Descriptor erstellen und braucht nicht extra den Owner anzugeben. In diesem Fall wird die SID des erstellenden Benutzers selbst zum Owner (Ausnahme: Wenn ein Mitglied der vordefinierten Administratoren ein Objekt erstellt, dann wird die Gruppe und nicht der Benutzer als Owner eingetragen).
GROUP_DEFAULTED 2 The Owner Group information is generated automatically. You can create a new security descriptor with this flag and do not need to specify the group of the owner. In this case, the SID of the primary group of the creating user is the group owner value.
DACL_DEFAULTED 8 Die DACL (also die Berechtigungen) werden automatisch von dem darüber liegenden Objekt geerbt. Man kann mit diesem Flag einen neuen Security Descriptor erstellen und ohne explizite eigenen Rechte die darüber liegenden Rechte einfach erben.
SACL_DEFAULTED 32 Die SACL (also die Audit-Einstellungen) werden automatisch von dem darüber liegenden Objekt geerbt. Man kann mit diesem Flag einen neuen Security Descriptor erstellen und ohne explizite eigenen Audit-Einstellungen die darüber liegenden Werte einfach erben.


Flags innerhalb von ACEs

Die hier beschriebenen Flags kommen je einmal pro Access Control Entry vor, es kann innerhalb des gesamten Security Descriptors also viele Vorkommnisse geben. Vorsicht, Verwechslungsgefahr: In ACEs kommen zwei Arten von Flags vor: Die "ACE Flags" und die "Flags". Sie steuern die Vererbungseinstellungen des betreffenden ACEs und aktivieren die im ACE evtl. vorhandenen Object Type Felder.

In jedem ACE gibt es die "ACE Flags", die Teil des technischen ACE Headers sind. Sie bestimmen die Art der Vererbung bei neuen ACEs oder geben die Situation der Vererbung wieder, wenn man den betreffenden ACE ausliest.

Flag

Abkürzung

in SDDL

Wert
(dez)
Wert
(hex)
Erklärung
ADS_ACEFLAG_INHERIT_ACE
  auch
CONTAINER_INHERIT_ACE
CI 2 2 Untergeordnete Objekte vererben die Berechtigung. Das Flag "Object Inherit (OI)", das bei Berechtigungen für Dateien und Verzeichnissen eine große Rolle spielt, wird für AD Rechte nicht benötigt, hier wird nur das "Container Inherit (CI)" verwendet. Es bezieht sich auf alle Objekte, auch solche, die keine Subobjekte unter sich haben.
ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE NP 4 4 Nur die direkt untergeordneten Objekte vererben die Berechtigung. Kann als Zusatz zum CI-Flag gesetzt werden.
ADS_ACEFLAG_INHERIT_ONLY_ACE IO 8 8 Die Berechtigung gilt nur für die untergeordneten Objekte, nicht jedoch für das eigentliche Objekt selbst. Kann als Zusatz zum CI-Flag gesetzt werden.
ADS_ACEFLAG_INHERITED_ACE ID 16 10 Diese Flag gibt an, dass es sich hier um eine von oben herab vererbte Berechtigung handelt. Dieses Flag kann nicht gesetzt werden, man kann es aber prüfen, um vererbte Rechte zu finden.


Es gibt dar?ber hinaus noch weitere Flag-Werte, die jedoch entweder in Active Directory ACLs nicht vorkommen, oder nicht f?r Berechtigungen, sondern f?r die Audit-Einstellungen in der SACL wichtig sind. Eine komplette Dokumentation der Flags finden Sie hier:

Das Weitergeben der Berechtigung an untergeordnete Objekte kann bei den komplexeren Object ACEs (ACE Typ 5 und 6) noch genauer angegeben werden. Es kann also festgelegt werden, dass ein Recht z.B. nur auf untergeordnete Benutzer-Objekte gelten soll, oder nur auf Gruppen. Dazu muss in den entsprechenden ACEs das Feld "Inherited Type" gesetzt sein. Ob dies der Fall ist, sieht man im so genannten "Flags" Feld:

Flag Bitwert Bedeutung
OBJECT_TYPE_PRESENT 1

Das Object Type Feld im ACE ist vorhanden und enth?lt eine Object GUID mit folgender Bedeutung

  • Bei Berechtigung zum Erstellen und L?schen von Child-Objekten kann hier die Objektart angegeben werden. Im Object Type Feld steht dann die GUID einer Objektklasse aus dem AD Schema.

  • Bei Berechtigung zum Lesen und Schreiben von Eigenschaften kann hier das Attribut oder das Propertyset angegeben werden, auf das sich das Recht bezieht. Im Object Type Feld steht dann die GUID eines Attributes aus dem Schema oder die GUID eines Property Sets aus der AD Configuration Partition (Container "Extended-Rights").

  • Bei erweiterten Rechten kann hier das konkrete Recht festgelegt werden. Im Object Type Feld steht dann die GUID eines erweiterten Rechtes aus der AD Configuration Partition (Container "Extended-Rights").
INHERITED_OBJECT_TYPE_PRESENT 2 Das Inherited Object Type Feld im ACE ist vorhanden und enthält eine Object GUID einer Objektklasse aus dem AD Schema.

Eine komplette Dokumentation der Flags finden Sie hier:


Liste der Berechtigungen - Access Mask Bits innerhalb von ACEs

Dies ist eine Liste der Berechtigungen auf Active Directory Verzeichnisobjekte, so wie sie in den oben beschriebenen Access Control Entries vorkommen oder gesetzt werden k?nnen. In manchen Access Masks k?nnen verschiedene Bits gleichzeitig gesetzt sein, z.B. kann in einem einzigen ACE festgelegt werden, dass jemand die Berechtigung hat, User-Objekte sowohl zu erstellen als auch zu l?schen (CC + DC). Es gibt jedoch auch offensichtliche Beschr?nkungen, denn in einem einzigen Objekt-ACE ist Platz f?r genau eine Object Type GUID, es ist also z.B. nicht m?glich das Recht zum L?schen von User-Objekten und zum Schreiben der Adresseigenschaften im gleichen ACE unterzubringen.

 

Die technische Beschreibung der Access Mask Bits bei Microsoft:

 

Berechtigung

Abk?rzung

in SDDL

Wert
(dez)
Wert
(hex)
Erkl?rung
ADS_RIGHT_DS_CREATE_CHILD CC 1 1 Untergeordnete Objekte erstellen. Dieses Recht kann noch auf bestimmte Objektklassen eingeschr?nkt sein. Die ACE-Eigenschaft ObjectType muss dann die GUID der entsprechenden Objektklasse beinhalten (SchemaIDGuid in der Klassendefinition des Schemas).
ADS_RIGHT_DS_DELETE_CHILD DC 2 2 Untergeordnete Objekte l?schen. Dieses Recht kann noch auf bestimmte Objektklassen eingeschr?nkt sein. Die ACE-Eigenschaft ObjectType muss dann die GUID der entsprechenden Objektklasse beinhalten (SchemaIDGuid).
ADS_RIGHT_ACTRL_DS_LIST LC 4 4 Untergeordnete Objekte auflisten.
ADS_RIGHT_DS_SELF WS

(auch SW)
8 8 So genannte "Validated Writes" ausf?hren. Dieses Recht kann noch auf bestimmte Validated Writes eingeschr?nkt sein, z.B. "Sich selbst als Mitglied hinzuf?gen", "Die eigene DNS-Adresseigenschaft eintragen" etc. Die ACE-Eigenschaft ObjectType muss dann die GUID des entsprechenden Extended Rights enthalten (RightsGuid aus der Configuration Partition \ Extended-Rights).
ADS_RIGHT_DS_READ_PROP RP 16 10 Eigenschaften (Properties) bzw. Attribute des betreffenden Objektes lesen. Dieses Recht kann noch auf bestimmte Attribute eingeschr?nkt sein. Die ACE-Eigenschaft ObjectType muss dann die GUID der entsprechenden Attribute beinhalten (SchemaIDGuid in der Attributdefinition des Schemas).
ADS_RIGHT_DS_WRITE_PROP WP 32 20 Eigenschaften (Properties) bzw. Attribute des betreffenden Objektes schreiben. Dieses Recht kann noch auf bestimmte Attribute eingeschr?nkt sein. Die ACE-Eigenschaft ObjectType muss dann die GUID der entsprechenden Attribute beinhalten (SchemaIDGuid in der Attributdefinition des Schemas).
ADS_RIGHT_DS_DELETE_TREE DT 64 40 Alle untergeordneten Objekte l?schen, egal ob und welche Berechtigungen dort herrschen.
ADS_RIGHT_DS_LIST_OBJECT LO 128 80 Das betreffende Objekt auflisten, obwohl im jeweiligen Container vielleicht das allgemeine Recht "ADS_RIGHT_ACTRL_DS_LIST" verweigert wurde. Es ist sozusagen ein Overwrite f?r einzelne Objekte, die dann sichtbar werden, obwohl der Rest des Containers versteckt ist. Diese Berechtigung wird nur wirksam, wenn das dritte dsHeuristics-Flag auf 1 gesetzt wird.
ADS_RIGHT_DS_CONTROL_ACCESS CA

(auch CR)
256 100 Erweiterte Rechte aus?ben. Dies kann noch auf einzelne erweiterte Rechte eingeschr?nkt werden, z.B. "Reset Password", "Change Rid Master", "Replication Synchronization", "Migrate SID History" etc. Die ACE-Eigenschaft ObjectType muss dann die GUID des entsprechenden Extended Rights enthalten (RightsGuid aus der Configuration Partition \ Extended-Rights).
ADS_RIGHT_DELETE DE 65536 10000 Das betreffende Objekt l?schen.
ADS_RIGHT_READ_CONTROL RC 131072 20000 Die Berechtigungen (DACL) und die Owner-Eigenschaften des betreffenden Objektes lesen.
ADS_RIGHT_WRITE_DAC WD 262144 40000 Die Berechtigungen (DACL) des betreffenden Objektes ?ndern. Beachten Sie, dass der Owner stets die DACL ?ndern kann, auch wenn er nicht explizit ?ber dieses Recht verf?gt.
ADS_RIGHT_WRITE_OWNER WO 524288 80000 Die Owner-Eigenschaft des betreffenden Objektes ?ndern.
ADS_RIGHT_SYNCHRONIZE SY 1048576 100000 Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen und auch nie selbst setzen. Ein generisches Recht, dass bei Verzeichnisobjekten nicht ben?tigt wird.
ADS_RIGHT_ACCESS_SYSTEM_SECURITY AS 16777216 1000000 Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen und es darf auch nie zum Setzen einer Berechtigung in einer DACL verwendet werden. Lediglich in SACLs f?r Audit-Einstellungen hat dieses Bit einen Sinn: Hier kann festgelegt werden, dass der Zugriff auf die SACL selbst aufgezeichnet wird.
ADS_RIGHT_GENERIC_ALL GA 268435456 10000000

Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen. Sie k?nnen es aber der Rechtevergabe jedoch verwenden, das System wandelt dies dann intern in die folgende Kombination "echter" AD-Objectrechte um:

ADS_RIGHT_DS_CREATE_CHILD +
ADS_RIGHT_DS_DELETE_CHILD +
ADS_RIGHT_ACTRL_DS_LIST +
ADS_RIGHT_DS_SELF +
ADS_RIGHT_DS_READ_PROP +
ADS_RIGHT_DS_WRITE_PROP +
ADS_RIGHT_DS_DELETE_TREE +
ADS_RIGHT_DS_LIST_OBJECT + ADS_RIGHT_DS_CONTROL_ACCESS +
ADS_RIGHT_DELETE +
ADS_RIGHT_READ_CONTROL +
ADS_RIGHT_WRITE_DAC +
ADS_RIGHT_WRITE_OWNER

ADS_RIGHT_GENERIC_EXECUTE GX 536870912 20000000 Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen. Sie k?nnen es ber der Rechtevergabe jedoch verwenden, das System wandelt dies dann intern in ADS_RIGHT_ACTRL_DS_LIST (Auflisten von untergeordneten Objekten) um.
ADS_RIGHT_GENERIC_WRITE GW 1073741824 40000000

Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen. Sie können es aber der Rechtevergabe jedoch verwenden, das System wandelt dies dann intern in die folgende Kombination "echter" AD-Objectrechte um:

ADS_RIGHT_DS_SELF +
ADS_RIGHT_DS_WRITE_PROP +
ADS_RIGHT_READ_CONTROL

ADS_RIGHT_GENERIC_READ GR 2147483648 80000000 Dieses Flag werden Sie beim Auslesen der Berechtigungen von AD-Objekten nie sehen. Sie können es aber der Rechtevergabe jedoch verwenden, das System wandelt dies dann intern in die folgende Kombination "echter" AD-Objectrechte um:

ADS_RIGHT_DS_READ_PROP +
ADS_RIGHT_ACTRL_DS_LIST +
ADS_RIGHT_READ_CONTROL



Object Type GUIDs innerhalb von ACEs

In komplexen ACEs des Typs 5 und 6 gibt es das Feld "Object Type GUID". Es kann drei Fälle geben bei denen diese Feld verwendet wird. Dabei muss dann das Flag OBJECT_TYPE_PRESENT (1) im betreffenden Access Control Entry gesetzt sein. Die GUID wird hier ürbigens einfach als String ausgelesen und gesetzt.


Inherited Type GUIDs innerhalb von ACEs

In komplexen ACEs des Typs 5 und 6 gibt es ds Feld "Inherited Object Type GUID". Es kann benutzt werden, um die Berechtigung nur auf spezielle Objektklassen zu vererben (z.B. "Der Displayname darf verändert werden, aber nur bei Gruppen!"). Dabei muss dann das Flag INHERITED_OBJECT_TYPE_PRESENT (2) im betreffenden Access Control Entry gesetzt sein. Im Inherited Object Type Feld steht dann die GUID einer Objektklasse aus dem AD Schema (SchemaIDGuid in der Klassendefinition des Schemas). Die GUID wird hier ürbigens einfach als String ausgelesen und gesetzt. Wichtige GUIDs wären hier:

Objektklasse GUID
Organizational Units bf967aa5-0de6-11d0-a285-00aa003049e2
Computer bf967a86-0de6-11d0-a285-00aa003049e2
User bf967aba-0de6-11d0-a285-00aa003049e2
Gruppen bf967a9c-0de6-11d0-a285-00aa003049e2
Kontakte 5cb41ed0-0e4c-11d0-a286-00aa003049e2


Trustees innerhalb von ACEs

In Access Control Entries (ACEs) ist stets auch der Trustee aufgeführt, das bedeutet der Account oder die Gruppe, für die Berechtigungen gewährt oder entzogen werden. Beim Setzen und Auslesen von Trustees können zwei Erscheinungsformen vorkommen:

Über den Aufbau von Microsoft SIDs und den Umgang damit handelt ein ausführlicher Tutorial-Artikel: "Microsoft Security Identifier (SID) Attribute".


Rechtevererbung

Bei der Vererbung der Berechtigungen für Active Directory Objekte gibt es verschiedene interessante Aspekte:

  1. Man möchte vielleicht per Script herausfinden, ob für ein Objekt die Vererbung von oben herab grundsätzlich deaktiviert/blockiert wurde. Dazu muss man einfach prüfen, ob das DACL_PROTECTED Bit in den ControlFlags des gesamten Security Descriptors gesetzt ist.

  2. Man möchte vielleicht per Script für eine einzelene bestehende Berechtigung herausfinden, ob diese von oben herab vererbt oder explizit gesetzt wurde. Dazu überprüfen Sie im betreffenden Access Control Entry, ob dort das INHERITED_ACE Flag in den ACEFlags gesetzt ist.

  3. Wenn man selbst neue Berechtigungen per Script setzt, möchte man bestimmen, ob und wie diese Berechtigung auf untergeordnete Objekte vererbt wird. Eine große Rolle spielen hierbei die Flags innerhalb der von Ihnen erzeugten ACEs. Dazu können Sie diese Matrix verwenden:

    Vererbungsreglen für Active Directory Access Control Entries

Active Directory Berechtigungen auslesen im Script

Hier ein Beispiel wie man die Berechtigung für ein einzelnes Objekt im Active Directory ausliest. Dazu wird das LDAP-Attribut nTSecurityDesriptor gelesen und ausgewertet:

'Sie müssen hier ein Objekt aus Ihrer eigene Umgebung angeben! Set obj = GetObject("LDAP://CN=test,OU=users,OU=example,DC=ldapexplorer,DC=com") Const ADS_FLAG_OBJECT_TYPE_PRESENT = 1 Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = 2 Set objACL = obj.get("nTSecurityDescriptor") Set objDACL = objACL.DiscretionaryAcl WScript.Echo obj.distinguishedname & vbCrLf Set ace = CreateObject("AccessControlEntry") For Each ace In objDACL WScript.Echo "__________________________________________________________________________________________________" 'Pure ACE-Daten ausgeben output = "ACEType: " & ace.AceType & ", ACEFlags: " & ace.AceFlags & ", Mask: " & ace.AccessMask If (ace.AceType = 5) Or (ace.AceType = 6) Then output = output & ", Flags: " & ace.Flags If ((ace.Flags And ADS_FLAG_OBJECT_TYPE_PRESENT) <> 0) Then    output = output & ", ObjectTypeGUID: " & ace.ObjectType End If If ((ace.Flags And ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT) <> 0) Then     output = output & ", InheritedObjectTypeGUID: " & ace.InheritedObjectType End If End If output = output & ", Trustee: " & ace.Trustee WScript.Echo output Next


Kompliziert wird das Ganze, wenn man eine genaue Auswertung der Berechtigungen und der Vererbung nach unten haben will. Das Script muss dafür nämlich die entprechenden GUIDs im Schema oder der Config Partition suchen und auswerten. Man beachte deswegen die beiden Functions decode_permission und decode_propagation.

Das Script muss auf einem Rechner der Domäne als Administrator ausgeführt werden.

'Sie müssen hier ein Objekt aus Ihrer eigene Umgebung angeben! Set obj = GetObject("LDAP://CN=test,OU=users,OU=example,DC=ldapexplorer,DC=com") Const ADS_ACETYPE_ACCESS_ALLOWED = 0 Const ADS_ACETYPE_ACCESS_DENIED = 1 Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 5 Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = 6 Const ADS_ACEFLAG_INHERITED_ACE = &H10 Const ADS_ACEFLAG_INHERIT_ACE = &H2 Const ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE = &H4 Const ADS_ACEFLAG_INHERIT_ONLY_ACE = &H8 Const ADS_RIGHT_DS_CREATE_CHILD = &H1 Const ADS_RIGHT_DS_DELETE_CHILD = &H2 Const ADS_RIGHT_ACTRL_DS_LIST = &H4 Const ADS_RIGHT_DS_SELF = &H8 Const ADS_RIGHT_DS_READ_PROP = &H10 Const ADS_RIGHT_DS_WRITE_PROP = &H20 Const ADS_RIGHT_DS_DELETE_TREE = &H40 Const ADS_RIGHT_DS_LIST_OBJECT = &H80 Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100 Const ADS_RIGHT_DELETE = &H10000 Const ADS_RIGHT_READ_CONTROL = &H20000 Const ADS_RIGHT_WRITE_DAC = &H40000 Const ADS_RIGHT_WRITE_OWNER = &H80000 Const ADS_RIGHT_GENERIC_ALL = &H10000000 Const ADS_RIGHT_GENERIC_WRITE = &H40000000 Const ADS_RIGHT_GENERIC_READ = &H80000000 Const ADS_FLAG_OBJECT_TYPE_PRESENT = 1 Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = 2 Set objACL = obj.get("nTSecurityDescriptor") Set objDACL = objACL.DiscretionaryAcl WScript.Echo obj.distinguishedname & vbCrLf Set ace = CreateObject("AccessControlEntry") For Each ace In objDACL WScript.Echo "__________________________________________________________________________________________________" '1) -> Zuerst: Pure ACE-Daten ausgeben output = "ACEType: " & ace.AceType & ", ACEFlags: " & ace.AceFlags & ", Mask: " & ace.AccessMask If (ace.AceType = 5) Or (ace.AceType = 6) Then output = output & ", Flags: " & ace.Flags If ((ace.Flags And ADS_FLAG_OBJECT_TYPE_PRESENT) <> 0) Then    output = output & ", ObjectTypeGUID: " & ace.ObjectType End If If ((ace.Flags And ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT) <> 0) Then     output = output & ", InheritedObjectTypeGUID: " & ace.InheritedObjectType End If End If output = output & ", Trustee: " & ace.Trustee WScript.Echo output '2) -> ACE-Typ entschlüsseln If ((ace.AceFlags And ADS_ACEFLAG_INHERITED_ACE) <> 0) Then WScript.Echo " Inherited" Else WScript.Echo " Directly" End If If (ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED) Or (ace.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT) Then output = "Grant " Else output = "Deny " End If output = output & "to " & ace.Trustee WScript.Echo " " & output '3) -> Berechtigungen entschlüsseln WScript.Echo " " & decode_permission(ace.AccessMask, ace.ObjectType) '4) -> Vererbungseinstellungen entschlüsseln WScript.Echo " " & decode_propagation(ace.AceFlags, ace.InheritedObjectType) Next Function decode_permission(mask, guid) 'wandelt einen Access Mask Zahlenwert in die Darstellung der entsprechenden Berechtigungen um classNeeded = (((mask And ADS_RIGHT_DS_CREATE_CHILD) <> 0) Or ((mask And ADS_RIGHT_DS_DELETE_CHILD) <> 0)) attributeNeeded = (((mask And ADS_RIGHT_DS_READ_PROP) <> 0) Or ((mask And ADS_RIGHT_DS_WRITE_PROP) <> 0)) extendedNeeded = ((mask And ADS_RIGHT_DS_CONTROL_ACCESS) <> 0) validatedNeeded = ((mask And ADS_RIGHT_DS_SELF) <> 0) guidExists = (Len(guid) > 0) 'objectTypeGuide verarbeiten... If (guidExists) Then If (classNeeded And attributeNeeded) Then objectclass = guid_to_class(ace.ObjectType) attribute = guid_to_attribute(ace.ObjectType) foundNoClass = (Left(objectclass, 1) = "{") foundNoAttribute = (Left(attribute, 1) = "{") If (foundNoClass And foundNoAttribute) Then objectclass = " (" & objectclass & ")" attribute = " (" & attribute & ")" ElseIf (foundNoClass) Then objectclass = " (All Classes)" attribute = "(" & attribute & ")" Else objectclass = " (" & objectclass & ")" attribute = " (All Properties)" End If ElseIf (classNeeded) Then objectclass = " (" & guid_to_class(ace.ObjectType) & ")" ElseIf (attributeNeeded) Then attribute = " (" & guid_to_attribute(ace.ObjectType) & ")" ElseIf (extendedNeeded) Then extended = " (" & guid_to_right(ace.ObjectType) & ")" ElseIf (validatedNeeded) Then validated = " (" & guid_to_right(ace.ObjectType) & ")" End If Else objectclass = " (All Classes)" attribute = " (All Properties)" extended = " (All Extended Rights)" validated = " (All validated Rights)" End If decode_permission = "" If ((mask And ADS_RIGHT_DS_CREATE_CHILD) <> 0) Then decode_permission = decode_permission & vbcrlf & " Create Child" & objectclass End If If ((mask And ADS_RIGHT_DS_DELETE_CHILD) <> 0) Then decode_permission = decode_permission & vbcrlf & " Delete Child" & objectclass End If If ((mask And ADS_RIGHT_ACTRL_DS_LIST) <> 0) Then decode_permission = decode_permission & vbcrlf & " List Childs" End If If ((mask And ADS_RIGHT_DS_SELF) <> 0) Then decode_permission = decode_permission & vbcrlf & " Validated Write" & validated End If If ((mask And ADS_RIGHT_DS_READ_PROP) <> 0) Then decode_permission = decode_permission & vbcrlf & " Read Property" & attribute End If If ((mask And ADS_RIGHT_DS_WRITE_PROP) <> 0) Then decode_permission = decode_permission & vbcrlf & " Write Property" & attribute End If If ((mask And ADS_RIGHT_DS_DELETE_TREE) <> 0) Then decode_permission = decode_permission & vbcrlf & " Delete Tree" End If If ((mask And ADS_RIGHT_DS_LIST_OBJECT) <> 0) Then decode_permission = decode_permission & vbcrlf & " List Object" End If If ((mask And ADS_RIGHT_DS_CONTROL_ACCESS) <> 0) Then decode_permission = decode_permission & vbcrlf & " Control Access" & extended End If If ((mask And ADS_RIGHT_DELETE) <> 0) Then decode_permission = decode_permission & vbcrlf & " Delete" End If If ((mask And ADS_RIGHT_READ_CONTROL) <> 0) Then decode_permission = decode_permission & vbcrlf & " Read Control" End If If ((mask And ADS_RIGHT_WRITE_DAC) <> 0) Then decode_permission = decode_permission & vbcrlf & " Write DAC" End If If ((mask And ADS_RIGHT_WRITE_OWNER) <> 0) Then decode_permission = decode_permission & vbcrlf & "Write Owner" End If If (Len(decode_permission) > 1) Then decode_permission = Mid(decode_permission, 7) End If End Function Function decode_propagation(flags, guid) 'wandelt die Einstellungen zur Vererbung eines ACEs "nach unten" in die entsprechende Darstellung um guidExists = (Len(guid) > 0) decode_propagation = "" If ((flags And ADS_ACEFLAG_INHERIT_ACE) = 0) Then decode_propagation = "This Object Only" Else If ((flags And ADS_ACEFLAG_INHERIT_ONLY_ACE) = 0) Then decode_propagation = decode_propagation & "Only " Else decode_propagation = "This object and " End If If ((flags And ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE) = 0) Then decode_propagation = decode_propagation & "only direct child objects" Else decode_propagation = decode_propagation & "child objects" End If If (guidExists) Then decode_propagation = decode_propagation & " (" & guid_to_class(guid) & ")" End If End If End Function Function guid_to_class(guidString) 'wandelt eine Object Class Schema-GUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" in den Namen der Klasse um 'Suchfilter erzeugen guidFilter = "(&(objectClass=classSchema)(schemaIDGUID=" & guid_to_filter(guidString) & "))" 'den Pfad zum Schema ermitteln Set rootDSE = GetObject("LDAP://rootDSE") schemaDN = rootDSE.Get("schemaNamingContext") 'Klasse suchen Set ado = CreateObject("ADODB.Connection") ado.Provider = "ADSDSOObject" ado.Open "ADSearch" On Error Resume Next Set classObj = ado.Execute("<LDAP://" & schemaDN & ">;" & guidFilter & ";lDAPDisplayName;onelevel") If (Err.Number = 0) And (classObj.RecordCount = 1) Then guid_to_class = CStr(classObj.Fields(0).Value) Else guid_to_class = Mid(guidString, 2, Len(guidString) - 2) End If End Function Function guid_to_attribute(guidString) 'wandelt eine Objectclass Schema-GUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" in ... '...den Namen des Attributs (oder Property Sets) um 'Suchfilter erzeugen guidFilter = "(&(objectClass=attributeSchema)(schemaIDGUID=" & guid_to_filter(guidString) & "))" 'den Pfad zum Schema ermitteln Set rootDSE = GetObject("LDAP://rootDSE") schemaDN = rootDSE.Get("schemaNamingContext") 'Klasse suchen Set ado = CreateObject("ADODB.Connection") ado.Provider = "ADSDSOObject" ado.Open "ADSearch" On Error Resume Next Set classObj = ado.Execute("<LDAP://" & schemaDN & ">;" & guidFilter & ";lDAPDisplayName;onelevel") If (Err.Number = 0) And (classObj.RecordCount = 1) Then guid_to_attribute = CStr(classObj.Fields(0).Value) Else 'kein Ergebnis => Wir suchen nach einem Property Set in der Config-Partition configDN = rootDSE.Get("configurationNamingContext") extendedDN = "CN=Extended-Rights," & configDN guidString = Mid(guidString, 2, Len(guidString) - 2) guidFilter = "(&(rightsGuid=" & guidString & ")(validAccesses=48))" Err.Clear Set classObj = ado.Execute("<LDAP://" & extendedDN & ">;" & guidFilter & ";displayName;onelevel") If (Err.Number = 0) And (classObj.RecordCount = 1) Then guid_to_attribute = CStr(classObj.Fields(0).Value) Else guid_to_attribute = guidString End If End If End Function Function guid_to_right(guidString) 'wandelt eine Object Class Schema-GUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" in den Namen ... '...des Extended Rights / Validated Write um 'Suchfilter erzeugen guidString = Mid(guidString, 2, Len(guidString) - 2) guidFilter = "(rightsGuid=" & guidString & ")" 'den Pfad zum Extended Rights Container ermitteln Set rootDSE = GetObject("LDAP://rootDSE") configDN = rootDSE.Get("configurationNamingContext") extendedDN = "CN=Extended-Rights," & configDN 'Extended Right suchen Set ado = CreateObject("ADODB.Connection") ado.Provider = "ADSDSOObject" ado.Open "ADSearch" On Error Resume Next Set classObj = ado.Execute("<LDAP://" & extendedDN & ">;" & guidFilter & ";displayName;onelevel") If (Err.Number = 0) And (classObj.RecordCount = 1) Then guid_to_right = CStr(classObj.Fields(0).Value) Else guid_to_right = guidString End If End Function Function guid_to_filter(guidString) 'wandelt eine Objectclass Schema-GUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" in einen '....entsprechenden LDAP-Suchfilter für Binär-Daten um guidValue = Array() ReDim guidValue(16) guidValue(0) = Mid(guidString, 8, 2) guidValue(1) = Mid(guidString, 6, 2) guidValue(2) = Mid(guidString, 4, 2) guidValue(3) = Mid(guidString, 2, 2) guidValue(4) = Mid(guidString, 13, 2) guidValue(5) = Mid(guidString, 11, 2) guidValue(6) = Mid(guidString, 18, 2) guidValue(7) = Mid(guidString, 16, 2) guidValue(8) = Mid(guidString, 21, 2) guidValue(9) = Mid(guidString, 23, 2) guidValue(10) = Mid(guidString, 26, 2) guidValue(11) = Mid(guidString, 28, 2) guidValue(12) = Mid(guidString, 30, 2) guidValue(13) = Mid(guidString, 32, 2) guidValue(14) = Mid(guidString, 34, 2) guidValue(15) = Mid(guidString, 36, 2) guid_to_filter = "" For i = 0 To 15 guid_to_filter = guid_to_filter & "\" & guidValue(i) Next End Function

Active Directory Berechtigungen setzen im Script

Hier ein Beispiel wie man die Berechtigung für ein einzelnes Objekt im Active Directory vergibt. Man liest für diesen Zweck das Attribut nTSecurityDesriptor aus und verändert dann die drin enthaltene DAC, indem man neue Access Control Entries hinzufügt. Später wird das gesamte Attribut wieder zurückgeschrieben.

Ein Trustee (also ein Benutzer oder eine Gruppe des gleichen AD Forests) bekommt Berechtigungen auf eine OU:

Man beachte hierbei die entsprechenden ACE-Flags und Object GUIDs, die für diesen Zweck verwendet werden. Das Script muss auf einem Rechner der Domäne als Administrator ausgeführt werden:

'Sie müssen hier ein Objekt und einen Trustee aus Ihrer eigene Umgebung angeben! Set obj = GetObject("LDAP://OU=users,OU=example,DC=ldapexplorer,DC=com") trustee = "LEX\AccessUser" Const ADS_REVISION_DS = 4 Const ADS_ACETYPE_ACCESS_ALLOWED = 0 Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = 5 Const ADS_ACEFLAG_INHERIT_ACE = &H2 Const ADS_ACEFLAG_INHERIT_ONLY_ACE = &H8 Const ADS_RIGHT_DS_READ_PROP = &H10 Const ADS_RIGHT_DS_WRITE_PROP = &H20 Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100 Const ADS_RIGHT_DELETE = &H10000 Const ADS_FLAG_OBJECT_TYPE_PRESENT = 1 Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = 2 Const GUID_ATTR_DESCRIPTION = "{bf967950-0de6-11d0-a285-00aa003049e2}" Const GUID_CLASS_USER = "{bf967aba-0de6-11d0-a285-00aa003049e2}" Const GUID_RIGHT_RESETPASSWORD = "{ab721a53-1e2f-11d0-9819-00aa0040529b}" Set objACL = obj.get("nTSecurityDescriptor") Set objDACL = objACL.DiscretionaryAcl WScript.Echo obj.distinguishedname & vbCrLf 'Neuen ACE-Eintrag erzeugen : OU löschen, nicht jedoch enthaltene Objekte Set newAce = CreateObject("AccessControlEntry") newAce.Trustee = trustee newAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED newAce.AceFlags = 0 newAce.AccessMask = ADS_RIGHT_DELETE newACE.Flags = 0 objDACL.AddAce newAce 'Neuen ACE-Eintrag erzeugen : "Description" Feld lesen/schreiben für alle enthaltenen Objekte Set newAce = CreateObject("AccessControlEntry") newAce.Trustee = trustee newAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT newAce.AceFlags = ADS_ACEFLAG_INHERIT_ACE Or ADS_ACEFLAG_INHERIT_ONLY_ACE newAce.AccessMask = ADS_RIGHT_DS_READ_PROP Or ADS_RIGHT_DS_WRITE_PROP newACE.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT newACE.ObjectType = GUID_ATTR_DESCRIPTION objDACL.AddAce newAce 'Neuen ACE-Eintrag erzeugen : Passwort zurücksetzen für Benutzer Set newAce = CreateObject("AccessControlEntry") newAce.Trustee = trustee newAce.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT newAce.AceFlags = ADS_ACEFLAG_INHERIT_ACE newAce.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS newACE.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT Or ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT newACE.ObjectType = GUID_RIGHT_RESETPASSWORD newACE.InheritedObjectType = GUID_CLASS_USER objDACL.AddAce newAce 'Neue DACL schreiben objACL.DiscretionaryAcl = objDACL obj.Put "ntSecurityDescriptor", objACL obj.SetInfo

Active Directory Berechtigungen entfernen im Script

Hier ein Beispiel wie man die Berechtigung für ein einzelnes Objekt im Active Directory entfernt. Man liest für diesen Zweck das Attribut nTSecurityDesriptor aus. Man liest aus der darin enthaltenen Discretionary Access Control List (DACL) alle ACEs aus, die nicht von oben vererbt werden, und die nicht dem Trustee zugeordnet sind, den man aus der Rechteliste entfernen will. Aus diesen ACEs baut man dann eine neue DACL zusammen. Bei Zurückschreiben des gesamten Attributes kommen dann die von oben vererbten Berechtigungen wieder automatisch dazu.

'Sie müssen hier ein Objekt und einen Trustee aus Ihrer eigene Umgebung angeben! Set obj = GetObject("LDAP://OU=users,OU=example,DC=ldapexplorer,DC=com") trustee = "LEX\AccessUser" Const ADS_REVISION_DS = 4 Set objACL = obj.get("nTSecurityDescriptor") Set objDACL = objACL.DiscretionaryAcl WScript.Echo obj.distinguishedname & vbCrLf Set newDACL = CreateObject("AccessControlList") newDACL.AclRevision = ADS_REVISION_DS newDACL.AceCount = 0 Set ace = CreateObject("AccessControlEntry") For Each ace In objDACL 'Alle bisherigen ACEs beibehalten, falls sie nicht vererbt sind oder nicht den Trustee enthalten If ((ace.AceFlags And ADS_ACEFLAG_INHERITED_ACE) <> 0) Or (ace.Trustee <> trustee) Then newDACL.AddAce ace End If Next 'Neue DACL schreiben objACL.DiscretionaryAcl = newDACL obj.Put "ntSecurityDescriptor", objACL obj.SetInfo