Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9df24ad4b0 | |||
| 0ab89e75b8 | |||
| 5e3d9d8618 | |||
| e7dcb39efb | |||
| 41e34976fc | |||
| a99c9e848c | |||
| e8a23e0ede | |||
| 125eea5afc |
Vendored
+16
@@ -1,3 +1,19 @@
|
||||
ldaptool (0.8-1) unstable; urgency=medium
|
||||
|
||||
* keyringer backend: handle 'Nothing matches' output, keyringer
|
||||
doesn't fail properly
|
||||
* use only first line from multi-line password entries (and strip
|
||||
whitespace)
|
||||
|
||||
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Wed, 21 Jan 2026 14:25:02 +0100
|
||||
|
||||
ldaptool (0.7-1) unstable; urgency=medium
|
||||
|
||||
* decode groupType
|
||||
* fix table outputs (join multiple values with separator again), use separate method for (simple) json
|
||||
|
||||
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Fri, 12 May 2023 11:17:24 +0200
|
||||
|
||||
ldaptool (0.6-1) unstable; urgency=medium
|
||||
|
||||
* move --json to --full_json; remove --human JSON output, replace with --json, but don't merge multiple values - use list instead
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from . import sid, timestamp, uac
|
||||
from . import grouptype, sid, timestamp, uac
|
||||
|
||||
__all__ = [
|
||||
"grouptype",
|
||||
"sid",
|
||||
"timestamp",
|
||||
"uac",
|
||||
|
||||
@@ -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)
|
||||
@@ -26,7 +26,10 @@ def search(*, config: Config, arguments: Arguments) -> typing.Iterable[Result]:
|
||||
if arguments.krb:
|
||||
ldap_con.sasl_gssapi_bind_s()
|
||||
else:
|
||||
ldap_con.simple_bind_s(realm.account, config.get_password(realm))
|
||||
password = config.get_password(realm)
|
||||
# use only first line (and without whitespace); assume remaining lines are comments/...
|
||||
password = password.splitlines()[0].strip()
|
||||
ldap_con.simple_bind_s(realm.account, password)
|
||||
|
||||
assert arguments.base
|
||||
assert arguments.filter
|
||||
|
||||
@@ -121,7 +121,10 @@ class Keyringer(PasswordManager):
|
||||
check=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
return result.stdout.strip()
|
||||
password = result.stdout.strip()
|
||||
if "Nothing matches , try again." in password:
|
||||
raise SystemExit(f"No password stored for {secretname}")
|
||||
return password
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
|
||||
Reference in New Issue
Block a user