Skip to content

Commit b66c61d

Browse files
authored
Improve more NTDS attributes (#55)
1 parent d25481c commit b66c61d

26 files changed

Lines changed: 532 additions & 65 deletions

‎dissect/database/ese/ntds/database.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from dissect.database.ese.ntds.query import Query
1212
from dissect.database.ese.ntds.schema import Schema
1313
from dissect.database.ese.ntds.sd import SecurityDescriptor
14-
from dissect.database.ese.ntds.util import DN, DatabaseFlags, SearchFlags, encode_value
14+
from dissect.database.ese.ntds.util import DN, DatabaseFlag, SearchFlag, encode_value
1515

1616
if TYPE_CHECKING:
1717
from collections.abc import Iterator
@@ -44,14 +44,14 @@ def __init__(self, fh: BinaryIO):
4444
self.data._make_dn.cache_clear()
4545

4646
@cached_property
47-
def flags(self) -> DatabaseFlags | None:
47+
def flags(self) -> DatabaseFlag | None:
4848
"""Return the database flags."""
4949
if self.hiddeninfo is None:
5050
return None
5151

52-
result = DatabaseFlags(0)
52+
result = DatabaseFlag(0)
5353
flags = self.hiddeninfo.get("flags_col")
54-
for idx, member in enumerate(DatabaseFlags.__members__.values()):
54+
for idx, member in enumerate(DatabaseFlag.__members__.values()):
5555
if flags[idx] == ord(b"1"):
5656
result = member if result is None else result | member
5757

@@ -256,9 +256,9 @@ def _get_index(self, attribute: str) -> Index:
256256
if schema.search_flags is None:
257257
raise ValueError(f"Attribute is not indexed: {attribute!r}")
258258

259-
if SearchFlags.Indexed in schema.search_flags:
259+
if SearchFlag.Indexed in schema.search_flags:
260260
name = f"INDEX_{schema.id:08x}"
261-
elif SearchFlags.TupleIndexed in schema.search_flags:
261+
elif SearchFlag.TupleIndexed in schema.search_flags:
262262
name = f"INDEX_T_{schema.id:08x}"
263263
else:
264264
# TODO add ContainerIndexed

‎dissect/database/ese/ntds/ntds.py‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
TrustedDomain,
2121
User,
2222
)
23+
from dissect.database.ese.ntds.objects.organizationalunit import OrganizationalUnit
2324
from dissect.database.ese.ntds.pek import PEK
2425

2526

@@ -83,19 +84,23 @@ def search(self, **kwargs: str) -> Iterator[Object]:
8384

8485
def groups(self) -> Iterator[Group]:
8586
"""Get all group objects from the database."""
86-
yield from self.search(objectCategory="group")
87+
yield from self.search(objectClass="group")
8788

8889
def servers(self) -> Iterator[Server]:
8990
"""Get all server objects from the database."""
90-
yield from self.search(objectCategory="server")
91+
yield from self.search(objectClass="server")
9192

9293
def users(self) -> Iterator[User]:
9394
"""Get all user objects from the database."""
9495
yield from self.search(objectCategory="person", objectClass="user")
9596

9697
def computers(self) -> Iterator[Computer]:
9798
"""Get all computer objects from the database."""
98-
yield from self.search(objectCategory="computer")
99+
yield from self.search(objectClass="computer")
100+
101+
def domains(self) -> Iterator[DomainDNS]:
102+
"""Get all domain objects from the database."""
103+
yield from self.search(objectClass="domainDNS")
99104

100105
def trusts(self) -> Iterator[TrustedDomain]:
101106
"""Get all trust objects from the database."""
@@ -105,6 +110,10 @@ def group_policies(self) -> Iterator[GroupPolicyContainer]:
105110
"""Get all group policy objects (GPO) objects from the database."""
106111
yield from self.search(objectClass="groupPolicyContainer")
107112

113+
def organizational_units(self) -> Iterator[OrganizationalUnit]:
114+
"""Get all organizational unit (OU) objects from the database."""
115+
yield from self.search(objectClass="organizationalUnit")
116+
108117
def secrets(self) -> Iterator[Secret]:
109118
"""Get all secret objects from the database."""
110119
yield from self.search(objectClass="secret")

‎dissect/database/ese/ntds/objects/attributeschema.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING, ClassVar
4+
35
from dissect.database.ese.ntds.objects.top import Top
6+
from dissect.database.ese.ntds.util import SearchFlag, SystemFlagAttribute
7+
8+
if TYPE_CHECKING:
9+
from dissect.database.ese.ntds.objects.object import DecoderMap
410

511

612
class AttributeSchema(Top):
@@ -11,3 +17,12 @@ class AttributeSchema(Top):
1117
"""
1218

1319
__object_class__ = "attributeSchema"
20+
__decoders__: ClassVar[DecoderMap] = {
21+
"searchFlags": lambda db, value: SearchFlag(value),
22+
"systemFlags": lambda db, value: SystemFlagAttribute(value),
23+
}
24+
25+
@property
26+
def search_flags(self) -> SearchFlag | None:
27+
"""Return the searchFlags of this attribute schema."""
28+
return self.get("searchFlags")

‎dissect/database/ese/ntds/objects/certificationauthority.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ class CertificationAuthority(Top):
1111
"""
1212

1313
__object_class__ = "certificationAuthority"
14+
15+
@property
16+
def dns_host_name(self) -> str | None:
17+
"""Return the dNSHostName of this Certification Authority."""
18+
return self.get("dNSHostName")

‎dissect/database/ese/ntds/objects/computer.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ class Computer(User):
2323
def __repr_body__(self) -> str:
2424
return f"name={self.name!r}"
2525

26+
@property
27+
def dns_host_name(self) -> str | None:
28+
"""Return the dNSHostName of this computer."""
29+
return self.get("dNSHostName")
30+
31+
@property
32+
def operating_system(self) -> str | None:
33+
"""Return the operatingSystem of this computer."""
34+
return self.get("operatingSystem")
35+
36+
@property
37+
def operating_system_version(self) -> str | None:
38+
"""Return the operatingSystemVersion of this computer."""
39+
return self.get("operatingSystemVersion")
40+
2641
def fve_recovery_information(self) -> Iterator[MSFVERecoveryInformation]:
2742
"""Return the BitLocker recovery information objects associated with this computer."""
2843
for child in self.children():

‎dissect/database/ese/ntds/objects/configuration.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ class Configuration(Top):
1111
"""
1212

1313
__object_class__ = "configuration"
14+
15+
@property
16+
def gp_link(self) -> str | None:
17+
"""Return the group policy link of the configuration."""
18+
return self.get("gPLink")

‎dissect/database/ese/ntds/objects/crossref.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING, ClassVar
4+
35
from dissect.database.ese.ntds.objects.top import Top
6+
from dissect.database.ese.ntds.util import SystemFlagCrossRef
7+
8+
if TYPE_CHECKING:
9+
from dissect.database.ese.ntds.objects.object import DecoderMap
410

511

612
class CrossRef(Top):
@@ -11,3 +17,11 @@ class CrossRef(Top):
1117
"""
1218

1319
__object_class__ = "crossRef"
20+
__decoders__: ClassVar[DecoderMap] = {
21+
"systemFlags": lambda db, value: SystemFlagCrossRef(value),
22+
}
23+
24+
@property
25+
def behavior_version(self) -> int | None:
26+
"""Return the msDS-Behavior-Version of this cross-reference."""
27+
return self.get("msDS-Behavior-Version")

‎dissect/database/ese/ntds/objects/crossrefcontainer.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ class CrossRefContainer(Top):
1111
"""
1212

1313
__object_class__ = "crossRefContainer"
14+
15+
@property
16+
def behavior_version(self) -> int | None:
17+
"""Return the msDS-Behavior-Version of this cross-reference container."""
18+
return self.get("msDS-Behavior-Version")

‎dissect/database/ese/ntds/objects/domaindns.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ def pek(self) -> PEK | None:
1919
if (pek := self.get("pekList")) is not None:
2020
return PEK(pek)
2121
return None
22+
23+
@property
24+
def behavior_version(self) -> int | None:
25+
"""Return the msDS-Behavior-Version of this domain DNS object."""
26+
return self.get("msDS-Behavior-Version")

‎dissect/database/ese/ntds/objects/group.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def sam_account_name(self) -> str:
2424
"""Return the group's sAMAccountName."""
2525
return self.get("sAMAccountName")
2626

27+
@property
28+
def mail(self) -> str | None:
29+
"""Return the mail address of this group."""
30+
return self.get("mail")
31+
32+
@property
33+
def admin_count(self) -> int | None:
34+
"""Return the group's adminCount."""
35+
return self.get("adminCount")
36+
2737
def managed_by(self) -> Iterator[Object]:
2838
"""Return the objects that manage this group."""
2939
self._assert_local()

0 commit comments

Comments
 (0)