Compare commits
8 Commits
34fcd259ef
...
debian/0.4
Author | SHA1 | Date | |
---|---|---|---|
18a27b195e | |||
6856c452e1 | |||
d9803c226e | |||
cbcdb36579 | |||
54a23e8060 | |||
d51d714352 | |||
474ee9383f | |||
71ab3043f4 |
38
debian/changelog
vendored
Normal file
38
debian/changelog
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
ldaptool (0.4-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* move argument/column handling to decoder (prepare for more post-processing in decoder)
|
||||||
|
* move json output format handling to main tool from decoder
|
||||||
|
* support attribute post-processing; :<len>, and DN :domain, :path, :fullpath
|
||||||
|
* use Enum instead of StrEnum for python3.10
|
||||||
|
|
||||||
|
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Tue, 02 May 2023 16:54:00 +0200
|
||||||
|
|
||||||
|
ldaptool (0.3-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* ldaptool: move output arguments from search to main
|
||||||
|
* run sort internally, refactor table output into separate method
|
||||||
|
* refactor table variant handling
|
||||||
|
* add html output format
|
||||||
|
* README.md: document csvkit dependency
|
||||||
|
* debian: require csvkit (markdown table is an essential feature)
|
||||||
|
|
||||||
|
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Fri, 28 Apr 2023 19:31:37 +0200
|
||||||
|
|
||||||
|
ldaptool (0.2-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* README.md: fix typo
|
||||||
|
* enable tls unless kerberos is used (SASL GSS-API doesn't seem to work over TLS)
|
||||||
|
|
||||||
|
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Fri, 28 Apr 2023 17:21:35 +0200
|
||||||
|
|
||||||
|
ldaptool (0.1-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Initial release.
|
||||||
|
|
||||||
|
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Fri, 28 Apr 2023 12:09:30 +0200
|
||||||
|
|
||||||
|
ldaptool (0.1-0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Stub ITP lintian.
|
||||||
|
|
||||||
|
-- Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de> Fri, 28 Apr 2023 12:09:29 +0200
|
43
debian/control
vendored
Normal file
43
debian/control
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Source: ldaptool
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de>
|
||||||
|
Rules-Requires-Root: no
|
||||||
|
Build-Depends:
|
||||||
|
debhelper-compat (= 13),
|
||||||
|
pybuild-plugin-pyproject,
|
||||||
|
flit,
|
||||||
|
dh-sequence-python3,
|
||||||
|
python3,
|
||||||
|
python3-ldap,
|
||||||
|
python3-yaml,
|
||||||
|
python3-pykeepass,
|
||||||
|
#Testsuite: autopkgtest-pkg-python
|
||||||
|
Standards-Version: 4.6.2
|
||||||
|
Homepage: https://git-nks-public.tik.uni-stuttgart.de/net/ldaptool
|
||||||
|
|
||||||
|
Package: python3-ldaptool
|
||||||
|
Architecture: all
|
||||||
|
Depends:
|
||||||
|
${python3:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
Recommends:
|
||||||
|
python3-pykeepass,
|
||||||
|
Description: CLI tool to run ldap queries
|
||||||
|
CLI tool to query LDAP/AD servers, featuring various output formats
|
||||||
|
and a configuration for different realms.
|
||||||
|
.
|
||||||
|
This package installs the library for Python 3.
|
||||||
|
|
||||||
|
Package: ldaptool
|
||||||
|
Architecture: all
|
||||||
|
Depends:
|
||||||
|
python3-ldaptool (=${binary:Version}),
|
||||||
|
${python3:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
csvkit,
|
||||||
|
Description: CLI tool to run ldap queries
|
||||||
|
CLI tool to query LDAP/AD servers, featuring various output formats
|
||||||
|
and a configuration for different realms.
|
||||||
|
.
|
||||||
|
This package installs the script.
|
27
debian/copyright
vendored
Normal file
27
debian/copyright
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Source: <https://git-nks-public.tik.uni-stuttgart.de/net/ldaptool>
|
||||||
|
Upstream-Name: ldaptool
|
||||||
|
|
||||||
|
Files:
|
||||||
|
*
|
||||||
|
Copyright:
|
||||||
|
2023 Stefan Bühler <stefan.buehler@tik.uni-stuttgart.de>
|
||||||
|
2023 Daniel Dizdarevic <daniel.dizdarevic@tik.uni-stuttgart.de>
|
||||||
|
License: MIT
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
.
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
5
debian/gbp.conf
vendored
Normal file
5
debian/gbp.conf
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
pristine-tar = False
|
||||||
|
upstream-branch = main
|
||||||
|
debian-branch = debian
|
||||||
|
upstream-tag = ldaptool-%(version)s
|
13
debian/rules
vendored
Executable file
13
debian/rules
vendored
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export PYBUILD_NAME=ldaptool
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --buildsystem=pybuild
|
||||||
|
|
||||||
|
# we want /usr/bin/ldaptool in a separate package
|
||||||
|
override_dh_auto_install:
|
||||||
|
dh_auto_install
|
||||||
|
|
||||||
|
mkdir -p debian/ldaptool/usr
|
||||||
|
mv debian/python3-ldaptool/usr/bin debian/ldaptool/usr/
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (quilt)
|
1
debian/source/options
vendored
Normal file
1
debian/source/options
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
extend-diff-ignore = "^[^/]*[.]egg-info/|^[.]vscode|/__pycache__/|^venv/|^.mypy_cache/"
|
@ -16,7 +16,7 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
dynamic = ["version", "description"]
|
dynamic = ["version", "description"]
|
||||||
|
|
||||||
requires-python = "~=3.10"
|
requires-python = "~=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"python-ldap",
|
"python-ldap",
|
||||||
"PyYAML",
|
"PyYAML",
|
||||||
|
@ -105,7 +105,7 @@ class _Context:
|
|||||||
try:
|
try:
|
||||||
self.config = search.Config.load()
|
self.config = search.Config.load()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise SystemExit(f"config error: {e!r}")
|
raise SystemExit(f"config error: {e}")
|
||||||
try:
|
try:
|
||||||
self.arguments = arguments_p.from_args(args)
|
self.arguments = arguments_p.from_args(args)
|
||||||
except decode.InvalidStep as e:
|
except decode.InvalidStep as e:
|
||||||
|
@ -7,7 +7,6 @@ import os
|
|||||||
import os.path
|
import os.path
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
@ -29,13 +28,13 @@ class Realm:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load(name: str, data: typing.Any) -> Realm:
|
def load(name: str, data: typing.Any) -> Realm:
|
||||||
assert isinstance(data, dict), f"Realm section isn't a dictionary: {data!r}"
|
assert isinstance(data, dict)
|
||||||
domain = data["domain"]
|
domain = data.pop("domain")
|
||||||
servers = data["servers"].split()
|
servers = data.pop("servers").split()
|
||||||
forest_root_domain = data.get("forest_root_domain", domain)
|
forest_root_domain = data.pop("forest_root_domain", domain)
|
||||||
account = data.get("account", None)
|
account = data.pop("account", None)
|
||||||
password_file = data.get("password_file", None)
|
password_file = data.pop("password_file", None)
|
||||||
password_folder = data.get("password_folder", None)
|
password_folder = data.pop("password_folder", None)
|
||||||
return Realm(
|
return Realm(
|
||||||
name=name,
|
name=name,
|
||||||
domain=domain,
|
domain=domain,
|
||||||
@ -102,8 +101,8 @@ class Keyringer(PasswordManager):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def load(data: typing.Any) -> Keyringer:
|
def load(data: typing.Any) -> Keyringer:
|
||||||
assert isinstance(data, dict)
|
assert isinstance(data, dict)
|
||||||
keyring = data["keyring"]
|
keyring = data.pop("keyring")
|
||||||
folder = data.get("folder", "")
|
folder = data.pop("folder")
|
||||||
return Keyringer(keyring=keyring, folder=folder)
|
return Keyringer(keyring=keyring, folder=folder)
|
||||||
|
|
||||||
def get_password(self, password_name: str) -> str:
|
def get_password(self, password_name: str) -> str:
|
||||||
@ -146,17 +145,9 @@ class Keepass(PasswordManager):
|
|||||||
def get_password(self, password_name: str) -> str:
|
def get_password(self, password_name: str) -> str:
|
||||||
import pykeepass # already made sure it is avaiable above
|
import pykeepass # already made sure it is avaiable above
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
password = getpass.getpass(f"KeePass password for database {self.database}: ")
|
password = getpass.getpass(f"KeePass password for database {self.database}: ")
|
||||||
kp = pykeepass.PyKeePass(self.database, password=password)
|
kp = pykeepass.PyKeePass(self.database, password=password)
|
||||||
break
|
|
||||||
except pykeepass.exceptions.CredentialsError:
|
|
||||||
print("Invalid password", file=sys.stderr)
|
|
||||||
|
|
||||||
entry = kp.find_entries(username=password_name, first=True)
|
entry = kp.find_entries(username=password_name, first=True)
|
||||||
if not entry:
|
|
||||||
raise SystemExit(f"no KeePass entry for {password_name!r} found")
|
|
||||||
return entry.password # type: ignore
|
return entry.password # type: ignore
|
||||||
|
|
||||||
|
|
||||||
@ -199,8 +190,8 @@ class Config:
|
|||||||
with open(conf_path) as f:
|
with open(conf_path) as f:
|
||||||
data = yaml.safe_load(f)
|
data = yaml.safe_load(f)
|
||||||
assert isinstance(data, dict)
|
assert isinstance(data, dict)
|
||||||
assert "realms" in data, "Missing realms section in config"
|
assert "realms" in data
|
||||||
realms_data = data["realms"]
|
realms_data = data.pop("realms")
|
||||||
assert isinstance(realms_data, dict)
|
assert isinstance(realms_data, dict)
|
||||||
realms = {}
|
realms = {}
|
||||||
for name, realm_data in realms_data.items():
|
for name, realm_data in realms_data.items():
|
||||||
@ -210,15 +201,15 @@ class Config:
|
|||||||
if "keyringer" in data:
|
if "keyringer" in data:
|
||||||
if password_manager:
|
if password_manager:
|
||||||
raise ValueError("Can only set a single password manager")
|
raise ValueError("Can only set a single password manager")
|
||||||
password_manager = Keyringer.load(data["keyringer"])
|
password_manager = Keyringer.load(data.pop("keyringer"))
|
||||||
if "keepass" in data:
|
if "keepass" in data:
|
||||||
if password_manager:
|
if password_manager:
|
||||||
raise ValueError("Can only set a single password manager")
|
raise ValueError("Can only set a single password manager")
|
||||||
password_manager = Keepass.load(data["keepass"])
|
password_manager = Keepass.load(data.pop("keepass"))
|
||||||
if "password-script" in data:
|
if "password-script" in data:
|
||||||
if password_manager:
|
if password_manager:
|
||||||
raise ValueError("Can only set a single password manager")
|
raise ValueError("Can only set a single password manager")
|
||||||
password_manager = PasswordScript.load(data["password-script"])
|
password_manager = PasswordScript.load(data.pop("password-script"))
|
||||||
|
|
||||||
return Config(realms=realms, password_manager=password_manager)
|
return Config(realms=realms, password_manager=password_manager)
|
||||||
|
|
||||||
@ -229,11 +220,7 @@ class Config:
|
|||||||
"""
|
"""
|
||||||
if realm.account is None:
|
if realm.account is None:
|
||||||
raise RuntimeError("Can't get password without acccount - should use kerberos instead")
|
raise RuntimeError("Can't get password without acccount - should use kerberos instead")
|
||||||
|
|
||||||
try:
|
|
||||||
if self.password_manager:
|
if self.password_manager:
|
||||||
return self.password_manager.get_password(realm.password_name)
|
return self.password_manager.get_password(realm.password_name)
|
||||||
|
|
||||||
return getpass.getpass(f"Enter password for {realm.password_name}: ")
|
return getpass.getpass(f"Enter password for {realm.password_name}: ")
|
||||||
except (KeyboardInterrupt, EOFError):
|
|
||||||
raise SystemExit("Password prompt / retrieval aborted")
|
|
||||||
|
Reference in New Issue
Block a user