diff --git a/src/ldaptool/decode/_decoder.py b/src/ldaptool/decode/_decoder.py index ad36bf9..43e4212 100644 --- a/src/ldaptool/decode/_decoder.py +++ b/src/ldaptool/decode/_decoder.py @@ -100,6 +100,13 @@ class Attribute: except Exception: return + def _try_decode_grouptype(self) -> None: + if self.utf8_clean: + try: + self.decoded = _types.grouptype.parse(self.utf8_clean.strip()) + except Exception: + return + def _try_decode(self, args: Arguments) -> None: if self.name in ("objectSid", "securityIdentifier"): self._try_decode_sid() @@ -115,6 +122,8 @@ class Attribute: self._try_decode_timestamp(args) elif self.name == "userAccountControl": self._try_decode_uac() + elif self.name == "groupType": + self._try_decode_grouptype() @property def _base64_value(self) -> str: @@ -190,13 +199,19 @@ class Decoder: return decoded_entry def human(self, *, dn: str, obj: TDecoded) -> dict[str, str]: + emit: dict[str, typing.Any] = dict(dn=dn) + for name, attrs in obj.items(): + emit[name] = self.arguments.human_separator.join(attr.human() for attr in attrs) + return emit + + def simple_json(self, *, dn: str, obj: TDecoded) -> dict[str, str]: emit: dict[str, typing.Any] = dict(dn=dn) for name, attrs in obj.items(): emit[name] = [attr.human() for attr in attrs] return emit def emit_simple_json(self, *, dn: str, obj: TDecoded, file: typing.IO[str] = sys.stdout) -> None: - emit = self.human(dn=dn, obj=obj) + emit = self.simple_json(dn=dn, obj=obj) json.dump(emit, file, ensure_ascii=False) print(file=file) # terminate output dicts by newline diff --git a/src/ldaptool/decode/_types/__init__.py b/src/ldaptool/decode/_types/__init__.py index 10adf6c..e60d093 100644 --- a/src/ldaptool/decode/_types/__init__.py +++ b/src/ldaptool/decode/_types/__init__.py @@ -1,8 +1,9 @@ from __future__ import annotations -from . import sid, timestamp, uac +from . import grouptype, sid, timestamp, uac __all__ = [ + "grouptype", "sid", "timestamp", "uac", diff --git a/src/ldaptool/decode/_types/grouptype.py b/src/ldaptool/decode/_types/grouptype.py new file mode 100644 index 0000000..fb5ad1a --- /dev/null +++ b/src/ldaptool/decode/_types/grouptype.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import enum +import typing + + +class GroupTypeFlags(enum.IntFlag): + SYSTEM = 0x00000001 + SCOPE_GLOBAL = 0x00000002 + SCOPE_DOMAIN = 0x00000004 + SCOPE_UNIVERSAL = 0x00000008 + APP_BASIC = 0x00000010 + APP_QUERY = 0x00000020 + SECURITY = 0x80000000 # otherwise distribution + + def flags(self) -> list[GroupTypeFlags]: + # ignore "uncovered" bits for now + value = self.value + members = [] + for member in GroupTypeFlags: + member_value = member.value + if member_value and member_value & value == member_value: + members.append(member) + return members + + +def parse(value: str) -> str: + members = GroupTypeFlags(int(value)).flags() + return ", ".join(typing.cast(str, member.name) for member in members)