# ldaptool CLI tool to query LDAP/AD servers * Configuration file to configure "realms" * DNS domain (mapping to ldap search base as DC labels) * LDAP servers in that domain * Bind account * Integration with password managers * Various output formats * Classic LDIF * JSON stream (with simplified or detailed attribute values) * CSV * Markdown table with stretched columns (for viewing in CLI/for monospaces fonts); requires csvlook from [csvkit](https://csvkit.readthedocs.io/) * HTML * Decodes certain well-known attributes (UUIDs, Timestamps, SID, userAccountControl) * Requires server to support [RFC 2696: Simple Paged Results](https://www.rfc-editor.org/rfc/rfc2696) for proper pagination * By default the first 1000 entries are shown, and it errors if there are more results * Use `--all` to show all results ## Virtual attributes `ldaptool` supports constructing new values from existing attributes by adding a `:` suffix (which can be chained apart from the length limit). * Some suffixes support an argument as `:[]`. * A single integer as postprocess suffix limits the length of the value; it replaces the last character of the output with `…` if it cut something off. * Multi-valued attributes generate multiple virtual attrites; each value is processed individually. (The values are joined afterwards for table output if needed.) ### DN handling DNs are decoded into lists of lists of `(name, value)` pairs (the inner list usually contains exactly one entry). Attributes with a `DC` name are considered part of the "domain", everything else belongs to the "path". (Usually a DN will start with path segments and end with domain segments.) The path is read from back to front. The following postprocess hooks are available: * `domain`: extracts the domain as DNS FQDN (`CN=Someone,OU=Dep1,DC=example,DC=com` becomes `example.com`) * `path`: extracts the non-domain parts without names and separates them by `/` (`CN=Someone,OU=Dep1,DC=example,DC=com` becomes `Dep1/Someone`) * `fullpath`: uses the `domain` as first segment in a path (`CN=Someone,OU=Dep1,DC=example,DC=com` becomes `example.com/Dep1/Someone`) * `dnslice`: extracts a "slice" from a DN (outer list only); the result is still in DN format. `path`, `fullpath` and `dnslice` take an optional index/slice as argument, written in python syntax. For `path` and `fullpath` this extracts only the given index/slice from the path (`fullpath` always includes the full FQDN as first segment), `dnslice` operates on the outer list of decoded (lists of) pairs: * `dn:dnslice[1:]` on `dn: CN=Someone,OU=Dep1,DC=example,DC=com` returns `OU=Dep1,DC=example,DC=com` * `dn:fullpath[:-1]` on `dn: CN=Someone,OU=Dep1,DC=example,DC=com` returns `example.com/Dep1` * `dn:path[-1]` on `dn: CN=Someone,OU=Dep1,DC=example,DC=com` returns `Someone` ## Authentication, Protocol, Ports `ldaptool` always uses TLS for password based authentication, and SASL GSS-API over non-TLS for Kerberos ones. ## Config file Location: `~/.config/ldaptool.yaml` ### Realms ```yaml realms: EXAMPLE: domain: "example.com" servers: server1 server2 account: "bind@example.com" password_folder: mainaccounts EXAMPLE.admin: domain: "example.com" servers: server1 server2 account: "CN=admin,OU=Admins,DC=example,DC=com" password_folder: adminaccounts EXAMPLE.admin2: domain: "example.com" servers: server1 server2 account: "CN=admin,OU=Admins,DC=example,DC=com" password_file: localadmin2 password_folder: adminaccounts SUB: domain: "sub.example.com" servers: subserver1 subserver2 forest_root_domain: "example.com" ``` The `servers` field is a whitespace separates list of hostnames in the domain. If a password manager is used, the `password_file` (defaults to names derived from `account`) and `password_folder` fields determine the name of the file ("secret") queried from the password manager. Here the following file names would be used: * `EXAMPLE`: `mainaccounts/bind` * `EXAMPLE.admin`: `adminaccounts/example.com/Admins/admin` * `EXAMPLE.admin2`: `adminaccounts/localadmin2` If the `account` field isn't present `ldaptool` always uses kerberos; if `--krb` is used, `account` is ignored. Windows AD has a concept of a "global catalog" across all domains in a AD Forest; it uses separate ports (3268 without TLS and 3269 with TLS). The `forest_root_domain` field can be used to set a search base for global catalog (`--gc`) queries (usually the forest root should be parent domain). Unless specified with `--base` the search base is derived from `domain` (or `forest_root_domain` with `--gc`) as `DC=...` for each DNS label. #### Script as password manager ```yaml password-script: keyring local decrypt ``` This configures a script as password manager. Either takes a string (split by [`shlex.split`](https://docs.python.org/3/library/shlex.html#shlex.split)) or a list of strings. The password name is appended as last argument. #### keyringer ```yaml keyringer: keyring: yourkeyringname folder: ldapquery ``` This configures [`keyringer`](https://0xacab.org/rhatto/keyringer) (based on GPG) as password manager. `keyringer` need a "keyring" to search in, and you can (optionally) specify a folder to be prefixed to the password names created from the realm. #### keepass ```yaml keepass: /home/me/mypasswords.kdbx ``` This configures KeePass as password manager; it will prompt for your master password every time.